-## Introduction
-
-This repository was created with the intention of helping developers master their concepts in JavaScript. It is not a requirement, but a guide for future studies. It is based on an article written by Stephen Curtis and you can read it [here](https://medium.com/@stephenthecurt/33-fundamentals-every-javascript-developer-should-know-13dd720a90d1).
-
-## Community
-
-Feel free to submit a PR by adding a link to your own recaps or reviews. If you want to translate the repo into your native language, please feel free to do so.
-
-All the translations for this repo will be listed below:
-
-- [اَلْعَرَبِيَّةُ (Arabic)](https://github.com/amrsekilly/33-js-concepts) — Amr Elsekilly
-- [Български (Bulgarian)](https://github.com/thewebmasterp/33-js-concepts) - thewebmasterp
-- [汉语 (Chinese)](https://github.com/stephentian/33-js-concepts) — Re Tian
-- [Português do Brasil (Brazilian Portuguese)](https://github.com/tiagoboeing/33-js-concepts) — Tiago Boeing
-- [한국어 (Korean)](https://github.com/yjs03057/33-js-concepts.git) — Suin Lee
-- [Español (Spanish)](https://github.com/adonismendozaperez/33-js-conceptos) — Adonis Mendoza
-- [Türkçe (Turkish)](https://github.com/ilker0/33-js-concepts) — İlker Demir
-- [русский язык (Russian)](https://github.com/gumennii/33-js-concepts) — Mihail Gumennii
-- [Tiếng Việt (Vietnamese)](https://github.com/nguyentranchung/33-js-concepts) — Nguyễn Trần Chung
-- [Polski (Polish)](https://github.com/lip3k/33-js-concepts) — Dawid Lipinski
-- [فارسی (Persian)](https://github.com/majidalavizadeh/33-js-concepts) — Majid Alavizadeh
-- [Bahasa Indonesia (Indonesian)](https://github.com/rijdz/33-js-concepts) — Rijdzuan Sampoerna
-- [Français (French)](https://github.com/robinmetral/33-concepts-js) — Robin Métral
-- [हिन्दी (Hindi)](https://github.com/vikaschauhan/33-js-concepts) — Vikas Chauhan
-- [Ελληνικά (Greek)](https://github.com/DimitrisZx/33-js-concepts) — Dimitris Zarachanis
-- [日本語 (Japanese)](https://github.com/oimo23/33-js-concepts) — oimo23
-- [Deutsch (German)](https://github.com/burhannn/33-js-concepts) — burhannn
-- [украї́нська мо́ва (Ukrainian)](https://github.com/AndrewSavetchuk/33-js-concepts-ukrainian-translation) — Andrew Savetchuk
-- [සිංහල (Sinhala)](https://github.com/ududsha/33-js-concepts) — Udaya Shamendra
-- [Italiano (Italian)](https://github.com/Donearm/33-js-concepts) — Gianluca Fiore
-- [Latviešu (Latvian)](https://github.com/ANormalStick/33-js-concepts) - Jānis Īvāns
-- [Afaan Oromoo (Oromo)](https://github.com/Amandagne/33-js-concepts) - Amanuel Dagnachew
-- [ภาษาไทย (Thai)](https://github.com/ninearif/33-js-concepts) — Arif Waram
-- [Català (Catalan)](https://github.com/marioestradaf/33-js-concepts) — Mario Estrada
-- [Svenska (Swedish)](https://github.com/FenixHongell/33-js-concepts/) — Fenix Hongell
-- [ខ្មែរ (Khmer)](https://github.com/Chhunneng/33-js-concepts) — Chrea Chanchhunneng
-- [አማርኛ (Ethiopian)](https://github.com/hmhard/33-js-concepts) - Miniyahil Kebede(ምንያህል ከበደ)
-- [Беларуская мова (Belarussian)](https://github.com/Yafimau/33-js-concepts) — Dzianis Yafimau
-- [O'zbekcha (Uzbek)](https://github.com/smnv-shokh/33-js-concepts) — Shokhrukh Usmonov
-- [Urdu (اردو)](https://github.com/sudoyasir/33-js-concepts) — Yasir Nawaz
-- [हिन्दी (Hindi)](https://github.com/milostivyy/33-js-concepts) — Mahima Chauhan
-- [বাংলা (Bengali)](https://github.com/Jisan-mia/33-js-concepts) — Jisan Mia
-- [ગુજરાતી (Gujarati)](https://github.com/VatsalBhuva11/33-js-concepts) — Vatsal Bhuva
-- [سنڌي (Sindhi)](https://github.com/Sunny-unik/33-js-concepts) — Sunny Gandhwani
-- [भोजपुरी (Bhojpuri)](https://github.com/debnath003/33-js-concepts) — Pronay Debnath
-- [ਪੰਜਾਬੀ (Punjabi)](https://github.com/Harshdev098/33-js-concepts) — Harsh Dev Pathak
-- [Latin (Latin)](https://github.com/Harshdev098/33-js-concepts) — Harsh Dev Pathak
-- [മലയാളം (Malayalam)](https://github.com/Stark-Akshay/33-js-concepts) — Akshay Manoj
-- [Yorùbá (Yoruba)](https://github.com/ayobaj/33-js-concepts) - Ayomide Bajulaye
-- [עברית (Hebrew)](https://github.com/rafyzg/33-js-concepts) — Refael Yzgea
-- [Nederlands (Dutch)](https://github.com/dlvisser/33-js-concepts) — Dave Visser
-- [தமிழ் (Tamil)] (https://github.com/UdayaKrishnanM/33-js-concepts) - Udaya Krishnan M
-
-
-
-## Table of Contents
-
-1. [**Call Stack**](#1-call-stack)
-2. [**Primitive Types**](#2-primitive-types)
-3. [**Value Types and Reference Types**](#3-value-types-and-reference-types)
-4. [**Implicit, Explicit, Nominal, Structuring and Duck Typing**](#4-implicit-explicit-nominal-structuring-and-duck-typing)
-5. [**== vs === vs typeof**](#5--vs--vs-typeof)
-6. [**Function Scope, Block Scope and Lexical Scope**](#6-function-scope-block-scope-and-lexical-scope)
-7. [**Expression vs Statement**](#7-expression-vs-statement)
-8. [**IIFE, Modules and Namespaces**](#8-iife-modules-and-namespaces)
-9. [**Message Queue and Event Loop**](#9-message-queue-and-event-loop)
-10. [**setTimeout, setInterval and requestAnimationFrame**](#10-settimeout-setinterval-and-requestanimationframe)
-11. [**JavaScript Engines**](#11-javascript-engines)
-12. [**Bitwise Operators, Type Arrays and Array Buffers**](#12-bitwise-operators-type-arrays-and-array-buffers)
-13. [**DOM and Layout Trees**](#13-dom-and-layout-trees)
-14. [**Factories and Classes**](#14-factories-and-classes)
-15. [**this, call, apply and bind**](#15-this-call-apply-and-bind)
-16. [**new, Constructor, instanceof and Instances**](#16-new-constructor-instanceof-and-instances)
-17. [**Prototype Inheritance and Prototype Chain**](#17-prototype-inheritance-and-prototype-chain)
-18. [**Object.create and Object.assign**](#18-objectcreate-and-objectassign)
-19. [**map, reduce, filter**](#19-map-reduce-filter)
-20. [**Pure Functions, Side Effects, State Mutation and Event Propagation**](#20-pure-functions-side-effects-state-mutation-and-event-propagation)
-21. [**Closures**](#21-closures)
-22. [**High Order Functions**](#22-high-order-functions)
-23. [**Recursion**](#23-recursion)
-24. [**Collections and Generators**](#24-collections-and-generators)
-25. [**Promises**](#25-promises)
-26. [**async/await**](#26-asyncawait)
-27. [**Data Structures**](#27-data-structures)
-28. [**Expensive Operation and Big O Notation**](#28-expensive-operation-and-big-o-notation)
-29. [**Algorithms**](#29-algorithms)
-30. [**Inheritance, Polymorphism and Code Reuse**](#30-inheritance-polymorphism-and-code-reuse)
-31. [**Design Patterns**](#31-design-patterns)
-32. [**Partial Applications, Currying, Compose and Pipe**](#32-partial-applications-currying-compose-and-pipe)
-33. [**Clean Code**](#33-clean-code)
-
-
-
-## 1. Call Stack
-
-
The call stack is a mechanism that the JavaScript interpreter uses to keep track of function execution within a program. In JavaScript, functions are executed in the order they are called. The call stack follows the Last In, First Out (LIFO) principle, meaning that the last function pushed onto the stack is the first one to be executed.
-
-
According to the ECMAScript specification, the call stack is defined as part of the execution context. Whenever a function is called, a new execution context is created and placed at the top of the stack. Once the function completes, its execution context is removed from the stack, and control returns to the previous context. This helps manage synchronous code execution, as each function call must complete before the next one can begin.
-
-### Reference
-
-- [Call Stack — MDN](https://developer.mozilla.org/en-US/docs/Glossary/Call_stack)
-
-### Articles
-
-- [Understanding Javascript Call Stack, Event Loops — Gaurav Pandvia](https://medium.com/@gaurav.pandvia/understanding-javascript-function-executions-tasks-event-loop-call-stack-more-part-1-5683dea1f5ec)
-- [Understanding the JavaScript Call Stack — Charles Freeborn](https://medium.freecodecamp.org/understanding-the-javascript-call-stack-861e41ae61d4)
-- [Javascript: What Is The Execution Context? What Is The Call Stack? — Valentino Gagliardi](https://medium.com/@valentinog/javascript-what-is-the-execution-context-what-is-the-call-stack-bd23c78f10d1)
-- [What is the JS Event Loop and Call Stack? — Jess Telford](https://gist.github.com/jesstelford/9a35d20a2aa044df8bf241e00d7bc2d0)
-- [Understanding Execution Context and Execution Stack in Javascript — Sukhjinder Arora](https://blog.bitsrc.io/understanding-execution-context-and-execution-stack-in-javascript-1c9ea8642dd0)
-- [How JavaScript Works Under The Hood: An Overview of JavaScript Engine, Heap and, Call Stack — Bipin Rajbhar](https://dev.to/bipinrajbhar/how-javascript-works-under-the-hood-an-overview-of-javascript-engine-heap-and-call-stack-1j5o)
-- [The JS Call stack Explained in 9 minutes](https://www.youtube.com/watch?v=W8AeMrVtFLY) - Colt Steel (YouTube)
-
-### Videos
-
-- [Javascript: the Call Stack explained — Coding Blocks India](https://www.youtube.com/watch?v=w6QGEiQceOM)
-- [The JS Call Stack Explained In 9 Minutes — Colt Steele](https://www.youtube.com/watch?v=W8AeMrVtFLY)
-- [What is the Call Stack? — Eric Traub](https://www.youtube.com/watch?v=w7QWQlkLY_s)
-- [The Call Stack — Kevin Drumm](https://www.youtube.com/watch?v=Q2sFmqvpBe0)
-- [Understanding JavaScript Execution — Codesmith](https://www.youtube.com/watch?v=Z6a1cLyq7Ac&list=PLWrQZnG8l0E4kd1T_nyuVoxQUaYEWFgcD)
-- [What the heck is the event loop anyway? — Philip Roberts](https://www.youtube.com/watch?v=8aGhZQkoFbQ)
-- [How JavaScript Code is executed? ❤️& Call Stack — Akshay Saini](https://www.youtube.com/watch?v=iLWTnMzWtj4&list=PLlasXeu85E9cQ32gLCvAvr9vNaUccPVNP)
-- [Call Stacks - CS50](https://www.youtube.com/watch?v=aCPkszeKRa4)
-- [Learn the JavaScript Call Stack - codecupdev](https://www.youtube.com/watch?v=HXqXPGS96rw)
-- [JavaScript Functions and the Call Stack | How does the Call stack work - Chidre'sTechTutorials](https://www.youtube.com/watch?v=P6H-T4cUDR4)
-
-**[⬆ Back to Top](#table-of-contents)**
-
----
-
-## 2. Primitive Types
-
-
According to the ECMAScript specification, JavaScript has six primitive data types: string, number, bigint, boolean, undefined, and symbol. These types are immutable, meaning their values cannot be altered. There is also a special primitive type called null, which represents the intentional absence of any object value.
-
-
Primitive values are directly assigned to a variable, and when you manipulate a primitive type, you're working directly on the value. Unlike objects, primitives do not have properties or methods, but JavaScript automatically wraps primitive values with object counterparts when necessary (e.g., when calling methods on strings).
-
-### Reference
-
-- [JavaScript data types and data structures — MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Primitive_values)
-
-### Articles
-
-- [Primitive and Non-primitive data-types in JavaScript - GeeksforGeeks](https://www.geeksforgeeks.org/primitive-and-non-primitive-data-types-in-javascript)
-- [How numbers are encoded in JavaScript — Dr. Axel Rauschmayer](http://2ality.com/2012/04/number-encoding.html)
-- [What Every JavaScript Developer Should Know About Floating Point Numbers — Chewxy](https://blog.chewxy.com/2014/02/24/what-every-javascript-developer-should-know-about-floating-point-numbers/)
-- [The Secret Life of JavaScript Primitives — Angus Croll](https://javascriptweblog.wordpress.com/2010/09/27/the-secret-life-of-javascript-primitives/)
-- [Primitive Types — Flow](https://flow.org/en/docs/types/primitives/)
-- [(Not) Everything in JavaScript is an Object — Daniel Li](https://dev.to/d4nyll/not-everything-in-javascript-is-an-object)
-- [JavaScript data types and data structures — MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Primitive_values)
-- [Diving Deeper in JavaScripts Objects — Arfat Salman](https://blog.bitsrc.io/diving-deeper-in-javascripts-objects-318b1e13dc12)
-- [The differences between Object.freeze() vs Const in JavaScript — Bolaji Ayodeji](https://medium.com/@bolajiayodeji/the-differences-between-object-freeze-vs-const-in-javascript-4eacea534d7c)
-- [Object to primitive conversion — JavaScript.Info](https://javascript.info/object-toprimitive)
-- [Methods of primitives - Javascript.info](https://javascript.info/primitives-methods)
-
-### Videos
-
-- [JavaScript Reference vs Primitive Types — Academind](https://www.youtube.com/watch?v=9ooYYRLdg_g)
-- [JavaScript Primitive Types — Simon Sez IT](https://www.youtube.com/watch?v=HsbWQsSCE5Y)
-- [Value Types and Reference Types in JavaScript — Programming with Mosh](https://www.youtube.com/watch?v=e-_mDyqm2oU)
-- [JavaScript Primitive Data Types — Avelx](https://www.youtube.com/watch?v=qw3j0A3DIzQ)
-- [Everything you never wanted to know about JavaScript numbers — Bartek Szopka](https://www.youtube.com/watch?v=MqHDDtVYJRI)
-- [What are variables in Javascript? — JS For Everyone](https://www.youtube.com/watch?v=B4Bbmei_thw)
-- [TIPOS DE DATOS PRIMITIVOS en JAVASCRIPT - La Cocina del Código](https://www.youtube.com/watch?v=cC65D2q5f8I)
-- [Data Type in JavaScript - ScholarHat](https://www.youtube.com/watch?v=aFDvBjVjCh8)
-
-**[⬆ Back to Top](#table-of-contents)**
-
----
-
-## 3. Value Types and Reference Types
-
-
According to the ECMAScript specification, value types are stored directly in the location that the variable accesses. These include types like number, string, boolean, undefined, bigint, symbol, and null. When you assign a value type to a variable, the value itself is stored.
-
-
Reference types, on the other hand, are objects stored in the heap. Variables assigned to reference types actually store references (pointers) to the objects, not the objects themselves. When you assign a reference type to another variable, both variables reference the same object in memory.
-
-### Articles
-
-- [Explaining Value vs. Reference in Javascript — Arnav Aggarwal](https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0)
-- [Primitive Types & Reference Types in JavaScript — Bran van der Meer](https://gist.github.com/branneman/7fb06d8a74d7e6d4cbcf75c50fec599c)
-- [Value Types, Reference Types and Scope in JavaScript — Ben Aston](https://medium.com/@benastontweet/lesson-1b-javascript-fundamentals-380f601ba851)
-- [Back to roots: JavaScript Value vs Reference — Miro Koczka](https://medium.com/dailyjs/back-to-roots-javascript-value-vs-reference-8fb69d587a18)
-- [Grasp "By Value" and "By Reference" in JavaScript — Léna Faure](https://hackernoon.com/grasp-by-value-and-by-reference-in-javascript-7ed75efa1293)
-- [JavaScript Reference and Copy Variables — Vítor Capretz](https://hackernoon.com/javascript-reference-and-copy-variables-b0103074fdf0)
-- [JavaScript Primitive vs Reference Values](http://www.javascripttutorial.net/javascript-primitive-vs-reference-values/)
-- [JavaScript by Reference vs. by Value — nrabinowitz](https://stackoverflow.com/questions/6605640/javascript-by-reference-vs-by-value)
-- [JavaScript Interview Prep: Primitive vs. Reference Types — Mike Cronin](https://dev.to/mostlyfocusedmike/javascript-interview-prep-primitive-vs-reference-types-3o4f)
-- [JavaScript map vs. forEach: When to Use Each One - Sajal Soni](https://code.tutsplus.com/tutorials/javascript-map-vs-foreach-when-to-use-each-one--cms-38365)
-
-### Videos
-
-- [Javascript Pass by Value vs Pass by Reference — techsith](https://www.youtube.com/watch?v=E-dAnFdq8k8)
-- [JavaScript Value vs Reference Types — Programming with Mosh](https://www.youtube.com/watch?v=fD0t_DKREbE)
-- [VALORES vs REFERENCIAS en JAVASCRIPT - La Cocina del Código](https://www.youtube.com/watch?v=AvkyOrWkuQc)
-- [JavaScript - Reference vs Primitive Values/ Types - Academind](https://www.youtube.com/watch?v=9ooYYRLdg_g)
-- [Value Types and Reference Types in JavaScript - Programming with Mosh](https://www.youtube.com/watch?v=e-_mDyqm2oU)
-
-**[⬆ Back to Top](#table-of-contents)**
-
----
-
-## 4. Implicit, Explicit, Nominal, Structuring and Duck Typing
-
-
The ECMAScript specification defines JavaScript as a dynamically typed language, meaning that types are associated with values rather than variables, and type checking occurs at runtime. There are various ways JavaScript manages types:
-
-
Implicit Typing (or Type Coercion): This occurs when JavaScript automatically converts one data type to another when required. For instance, JavaScript might convert a string to a number during an arithmetic operation. While this can simplify some code, it can also lead to unexpected results if not handled carefully.
-
-
Explicit Typing: Unlike implicit typing, explicit typing involves manually converting a value from one type to another using functions like Number(), String(), or Boolean().
-
-
Nominal Typing: JavaScript doesn't natively support nominal typing, where types are explicitly declared and checked. However, TypeScript, a superset of JavaScript, brings this feature to help catch type errors during development.
-
-
Structural Typing: In this type system, types are based on the structure or properties of the data. JavaScript is a structurally typed language where objects are compatible if they share the same structure (i.e., the same set of properties and methods).
-
-
Duck Typing: This is a concept where an object's suitability is determined by the presence of certain properties and methods, rather than by the actual type of the object. JavaScript relies heavily on duck typing, where behavior is inferred from an object's properties rather than its declared type.
If you find this repository helpful, please consider giving it a star!
+ If you find this helpful, please star the repo!
diff --git a/TRANSLATIONS.md b/TRANSLATIONS.md
new file mode 100644
index 00000000..98374658
--- /dev/null
+++ b/TRANSLATIONS.md
@@ -0,0 +1,54 @@
+# Translations
+
+This project has been translated into 40+ languages thanks to our amazing community of contributors.
+
+## Available Translations
+
+- [اَلْعَرَبِيَّةُ (Arabic)](https://github.com/amrsekilly/33-js-concepts) — Amr Elsekilly
+- [Български (Bulgarian)](https://github.com/thewebmasterp/33-js-concepts) — thewebmasterp
+- [汉语 (Chinese)](https://github.com/stephentian/33-js-concepts) — Re Tian
+- [Português do Brasil (Brazilian Portuguese)](https://github.com/tiagoboeing/33-js-concepts) — Tiago Boeing
+- [한국어 (Korean)](https://github.com/yjs03057/33-js-concepts.git) — Suin Lee
+- [Español (Spanish)](https://github.com/adonismendozaperez/33-js-conceptos) — Adonis Mendoza
+- [Türkçe (Turkish)](https://github.com/ilker0/33-js-concepts) — İlker Demir
+- [русский язык (Russian)](https://github.com/gumennii/33-js-concepts) — Mihail Gumennii
+- [Tiếng Việt (Vietnamese)](https://github.com/nguyentranchung/33-js-concepts) — Nguyễn Trần Chung
+- [Polski (Polish)](https://github.com/lip3k/33-js-concepts) — Dawid Lipinski
+- [فارسی (Persian)](https://github.com/majidalavizadeh/33-js-concepts) — Majid Alavizadeh
+- [Bahasa Indonesia (Indonesian)](https://github.com/rijdz/33-js-concepts) — Rijdzuan Sampoerna
+- [Français (French)](https://github.com/robinmetral/33-concepts-js) — Robin Métral
+- [हिन्दी (Hindi)](https://github.com/vikaschauhan/33-js-concepts) — Vikas Chauhan
+- [Ελληνικά (Greek)](https://github.com/DimitrisZx/33-js-concepts) — Dimitris Zarachanis
+- [日本語 (Japanese)](https://github.com/oimo23/33-js-concepts) — oimo23
+- [Deutsch (German)](https://github.com/burhannn/33-js-concepts) — burhannn
+- [украї́нська мо́ва (Ukrainian)](https://github.com/AndrewSavetchuk/33-js-concepts-ukrainian-translation) — Andrew Savetchuk
+- [සිංහල (Sinhala)](https://github.com/ududsha/33-js-concepts) — Udaya Shamendra
+- [Italiano (Italian)](https://github.com/Donearm/33-js-concepts) — Gianluca Fiore
+- [Latviešu (Latvian)](https://github.com/ANormalStick/33-js-concepts) — Jānis Īvāns
+- [Afaan Oromoo (Oromo)](https://github.com/Amandagne/33-js-concepts) — Amanuel Dagnachew
+- [ภาษาไทย (Thai)](https://github.com/ninearif/33-js-concepts) — Arif Waram
+- [Català (Catalan)](https://github.com/marioestradaf/33-js-concepts) — Mario Estrada
+- [Svenska (Swedish)](https://github.com/FenixHongell/33-js-concepts/) — Fenix Hongell
+- [ខ្មែរ (Khmer)](https://github.com/Chhunneng/33-js-concepts) — Chrea Chanchhunneng
+- [አማርኛ (Ethiopian)](https://github.com/hmhard/33-js-concepts) — Miniyahil Kebede (ምንያህል ከበደ)
+- [Беларуская мова (Belarussian)](https://github.com/Yafimau/33-js-concepts) — Dzianis Yafimau
+- [O'zbekcha (Uzbek)](https://github.com/smnv-shokh/33-js-concepts) — Shokhrukh Usmonov
+- [Urdu (اردو)](https://github.com/sudoyasir/33-js-concepts) — Yasir Nawaz
+- [हिन्दी (Hindi)](https://github.com/milostivyy/33-js-concepts) — Mahima Chauhan
+- [বাংলা (Bengali)](https://github.com/Jisan-mia/33-js-concepts) — Jisan Mia
+- [ગુજરાતી (Gujarati)](https://github.com/VatsalBhuva11/33-js-concepts) — Vatsal Bhuva
+- [سنڌي (Sindhi)](https://github.com/Sunny-unik/33-js-concepts) — Sunny Gandhwani
+- [भोजपुरी (Bhojpuri)](https://github.com/debnath003/33-js-concepts) — Pronay Debnath
+- [ਪੰਜਾਬੀ (Punjabi)](https://github.com/Harshdev098/33-js-concepts) — Harsh Dev Pathak
+- [Latin (Latin)](https://github.com/Harshdev098/33-js-concepts) — Harsh Dev Pathak
+- [മലയാളം (Malayalam)](https://github.com/Stark-Akshay/33-js-concepts) — Akshay Manoj
+- [Yorùbá (Yoruba)](https://github.com/ayobaj/33-js-concepts) — Ayomide Bajulaye
+- [עברית (Hebrew)](https://github.com/rafyzg/33-js-concepts) — Refael Yzgea
+- [Nederlands (Dutch)](https://github.com/dlvisser/33-js-concepts) — Dave Visser
+- [தமிழ் (Tamil)](https://github.com/UdayaKrishnanM/33-js-concepts) — Udaya Krishnan M
+
+---
+
+## Want to Translate?
+
+We'd love to have more translations! See our [Contributing Guidelines](CONTRIBUTING.md) for details on how to submit a translation.
diff --git a/docs/concepts/algorithms-big-o.mdx b/docs/concepts/algorithms-big-o.mdx
new file mode 100644
index 00000000..db6665c9
--- /dev/null
+++ b/docs/concepts/algorithms-big-o.mdx
@@ -0,0 +1,660 @@
+---
+title: "Algorithms & Big O: Measuring Code Performance in JavaScript"
+sidebarTitle: "Algorithms & Big O: Measuring Code Performance"
+description: "Learn Big O notation and algorithms in JavaScript. Understand time complexity, implement searching and sorting algorithms, and recognize common interview patterns."
+---
+
+Why 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:
+
+```javascript
+// Approach A: Nested loops
+function hasDuplicatesA(arr) {
+ for (let i = 0; i < arr.length; i++) {
+ for (let j = i + 1; j < arr.length; j++) {
+ if (arr[i] === arr[j]) return true
+ }
+ }
+ return false
+}
+
+// Approach B: Using a Set
+function hasDuplicatesB(arr) {
+ return new Set(arr).size !== arr.length
+}
+```
+
+Both 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.
+
+
+**What you'll learn in this guide:**
+- What Big O notation actually measures
+- The common complexities: O(1), O(log n), O(n), O(n log n), O(n²)
+- How to analyze your own code's complexity
+- JavaScript built-in methods and their complexity
+- Implementing binary search and merge sort
+- Common interview patterns: two pointers, sliding window, frequency counter
+
+
+
+**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.
+
+
+---
+
+## What is Big O Notation?
+
+**Big O notation** describes how an algorithm's runtime or space requirements grow as input size increases. It provides an upper bound on growth rate and ignores constants, giving us a way to compare algorithms regardless of hardware.
+
+### The Package Delivery Analogy
+
+Imagine you need to deliver packages to houses on a street:
+
+- **O(1)**: You have the exact address. Go directly there. Whether there are 10 or 10,000 houses, it takes the same time.
+- **O(n)**: You check each house until you find the right one. More houses = proportionally more time.
+- **O(n²)**: For each house, you compare it with every other house. 10 houses = 100 comparisons. 100 houses = 10,000 comparisons.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ HOW ALGORITHMS SCALE │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Operations │
+│ ▲ │
+│ │ O(n²) │
+│ 1M │ •••• │
+│ │ ••• │
+│ │ ••• │
+│ │ ••• │
+│ 100K │ •••• O(n log n) │
+│ │ ••• ════════════ │
+│ │ •••• ═════ │
+│ │ •••• ═════ │
+│ 10K │ ••••• ═════ O(n) │
+│ │ •••• ═════ ────────────── │
+│ │ •••• ═════ ─────── │
+│ │ •••• ═════ ─────── O(log n) │
+│ 1K │•••• ═════ ────── ............ │
+│ │═════ ─────── ........ │
+│ │ ────── .......... O(1) │
+│ 100 │──── .......... ══════════════ │
+│ └──────────────────────────────────────────────────────────► │
+│ 100 1K 10K 100K 1M Input (n) │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## The Big O Complexity Scale
+
+Here are the most common complexities you'll encounter, from fastest to slowest:
+
+| Complexity | Name | Example | 1,000 items | 1,000,000 items |
+|------------|------|---------|-------------|-----------------|
+| O(1) | Constant | Array access | 1 op | 1 op |
+| O(log n) | Logarithmic | Binary search | ~10 ops | ~20 ops |
+| O(n) | Linear | Simple loop | 1,000 ops | 1,000,000 ops |
+| O(n log n) | Linearithmic | Merge sort | ~10,000 ops | ~20,000,000 ops |
+| O(n²) | Quadratic | Nested loops | 1,000,000 ops | 1,000,000,000,000 ops |
+
+
+
+ The operation takes the same time regardless of input size.
+
+ ```javascript
+ // Array access by index
+ const arr = [1, 2, 3, 4, 5]
+ const element = arr[2] // O(1) - instant, no matter array size
+
+ // Object/Map lookup
+ const user = { name: 'Alice', age: 30 }
+ const name = user.name // O(1)
+
+ const map = new Map()
+ map.set('key', 'value')
+ map.get('key') // O(1)
+
+ // Array push and pop (end operations)
+ arr.push(6) // O(1)
+ arr.pop() // O(1)
+ ```
+
+
+
+ Time increases slowly as input grows. Each step eliminates half the remaining data. This is the "sweet spot" for searching sorted data.
+
+ ```javascript
+ // Binary search - covered in detail below
+ // With 1,000,000 elements, only ~20 comparisons needed!
+
+ // Think of it like a phone book:
+ // Open middle → wrong half eliminated → repeat
+ ```
+
+
+
+ Time grows proportionally with input. If you double the input, you double the time.
+
+ ```javascript
+ // Finding maximum value
+ function findMax(arr) {
+ let max = arr[0]
+ for (let i = 1; i < arr.length; i++) { // Visits each element once
+ if (arr[i] > max) max = arr[i]
+ }
+ return max
+ }
+
+ // Most array methods are O(n)
+ arr.indexOf(5) // O(n) - may check every element
+ arr.includes(5) // O(n)
+ arr.find(x => x > 3) // O(n)
+ arr.filter(x => x > 3) // O(n)
+ arr.map(x => x * 2) // O(n)
+ ```
+
+
+
+ Common for efficient sorting algorithms. Faster than O(n²), but slower than O(n).
+
+ ```javascript
+ // JavaScript's built-in sort is O(n log n)
+ const sorted = [...arr].sort((a, b) => a - b)
+
+ // Merge sort and quick sort (average case) are also O(n log n)
+ ```
+
+
+
+ Time grows with the square of input. Nested loops over the same data are the typical culprit. **Avoid for large datasets.**
+
+ ```javascript
+ // Checking all pairs
+ function findPairs(arr) {
+ const pairs = []
+ for (let i = 0; i < arr.length; i++) { // O(n)
+ for (let j = i + 1; j < arr.length; j++) { // O(n) for each i
+ pairs.push([arr[i], arr[j]])
+ }
+ }
+ return pairs // Total: O(n) × O(n) = O(n²)
+ }
+
+ // Bubble sort - O(n²), mostly used for teaching
+ ```
+
+
+
+---
+
+## How to Analyze Your Code
+
+Follow these steps to determine your code's complexity:
+
+
+
+ What variable represents n? Usually it's array length or a number parameter.
+
+
+
+ - One loop over n elements = O(n)
+ - Nested loops = multiply: O(n) × O(n) = O(n²)
+ - Loop that halves each time = O(log n)
+
+
+
+ - O(2n) → O(n)
+ - O(n² + n) → O(n²)
+ - O(500) → O(1)
+
+
+
+```javascript
+// Example analysis
+function example(arr) {
+ console.log(arr[0]) // O(1)
+
+ for (let i = 0; i < arr.length; i++) { // O(n)
+ console.log(arr[i])
+ }
+
+ for (let i = 0; i < arr.length; i++) { // O(n)
+ for (let j = 0; j < arr.length; j++) { // × O(n)
+ console.log(arr[i], arr[j])
+ }
+ }
+}
+// Total: O(1) + O(n) + O(n²) = O(n²)
+// The n² dominates, so we say this function is O(n²)
+```
+
+---
+
+## JavaScript Built-in Methods Complexity
+
+Knowing these helps you make better decisions:
+
+### Array Methods
+
+| Method | Complexity | Why |
+|--------|------------|-----|
+| `push()`, `pop()` | O(1) | End operations, no shifting |
+| `shift()`, `unshift()` | O(n) | Must re-index all elements |
+| `splice()` | O(n) | May shift elements |
+| `slice()` | O(n) | Creates copy of portion |
+| `indexOf()`, `includes()` | O(n) | Linear search |
+| `find()`, `findIndex()` | O(n) | Linear search |
+| `map()`, `filter()`, `forEach()` | O(n) | Visits each element |
+| `sort()` | O(n log n) | Implementation varies by browser |
+
+### Object, Map, and Set
+
+| Operation | Object | Map | Set |
+|-----------|--------|-----|-----|
+| Get/Set/Has | O(1) | O(1) | O(1) |
+| Delete | O(1) | O(1) | O(1) |
+| Keys/Values | O(n) | O(n) | O(n) |
+
+
+**Use Set.has() instead of Array.includes()** when checking membership repeatedly. Set lookups are O(1) while array searches are O(n).
+
+
+---
+
+## Searching Algorithms
+
+### Linear Search - O(n)
+
+Check each element one by one. Simple but slow for large arrays.
+
+```javascript
+function linearSearch(arr, target) {
+ for (let i = 0; i < arr.length; i++) {
+ if (arr[i] === target) return i
+ }
+ return -1
+}
+
+linearSearch([3, 7, 1, 9, 4], 9) // Returns 3
+```
+
+### Binary Search - O(log n)
+
+Divide and conquer on a **sorted** array. Eliminates half the remaining elements each step.
+
+```javascript
+function binarySearch(arr, target) {
+ let left = 0
+ let right = arr.length - 1
+
+ while (left <= right) {
+ const mid = Math.floor((left + right) / 2)
+
+ if (arr[mid] === target) return mid
+ if (arr[mid] < target) left = mid + 1
+ else right = mid - 1
+ }
+
+ return -1
+}
+
+binarySearch([1, 3, 5, 7, 9, 11, 13], 9) // Returns 4
+```
+
+
+**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.
+
+
+---
+
+## Sorting Algorithms
+
+### Quick Reference
+
+| Algorithm | Best | Average | Worst | Space | Use When |
+|-----------|------|---------|-------|-------|----------|
+| Bubble Sort | O(n)* | O(n²) | O(n²) | O(1) | Never in production |
+| Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Need guaranteed performance |
+| Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n)** | General purpose |
+| JS `sort()` | O(n log n) | O(n log n) | O(n log n) | O(n) | Most cases |
+
+*Bubble sort achieves O(n) best case only with early termination optimization (when no swaps needed).
+**Quick sort space is O(log n) average case, O(n) worst case due to recursion stack depth.
+
+### Bubble Sort - O(n²)
+
+Repeatedly swaps adjacent elements if they're in wrong order. Educational, but too slow for real use.
+
+```javascript
+function bubbleSort(arr) {
+ const result = [...arr]
+ const n = result.length
+
+ for (let i = 0; i < n; i++) {
+ let swapped = false
+
+ for (let j = 0; j < n - i - 1; j++) {
+ if (result[j] > result[j + 1]) {
+ [result[j], result[j + 1]] = [result[j + 1], result[j]]
+ swapped = true
+ }
+ }
+
+ // If no swaps occurred, array is sorted
+ if (!swapped) break
+ }
+
+ return result
+}
+```
+
+### Merge Sort - O(n log n)
+
+Divide array in half, sort each half, merge them back. Consistent performance with guaranteed O(n log n).
+
+```javascript
+function mergeSort(arr) {
+ if (arr.length <= 1) return arr
+
+ const mid = Math.floor(arr.length / 2)
+ const left = mergeSort(arr.slice(0, mid))
+ const right = mergeSort(arr.slice(mid))
+
+ return merge(left, right)
+}
+
+function merge(left, right) {
+ const result = []
+ let i = 0
+ let j = 0
+
+ while (i < left.length && j < right.length) {
+ if (left[i] <= right[j]) {
+ result.push(left[i])
+ i++
+ } else {
+ result.push(right[j])
+ j++
+ }
+ }
+
+ return result.concat(left.slice(i)).concat(right.slice(j))
+}
+
+mergeSort([38, 27, 43, 3, 9, 82, 10]) // [3, 9, 10, 27, 38, 43, 82]
+```
+
+
+**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.
+
+
+---
+
+## Common Interview Patterns
+
+These patterns solve many algorithm problems efficiently.
+
+### Two Pointers - O(n)
+
+Use two pointers moving toward each other or in the same direction. Great for sorted arrays and finding pairs.
+
+```javascript
+// Find pair that sums to target in sorted array
+function twoSum(arr, target) {
+ let left = 0
+ let right = arr.length - 1
+
+ while (left < right) {
+ const sum = arr[left] + arr[right]
+
+ if (sum === target) return [left, right]
+ if (sum < target) left++
+ else right--
+ }
+
+ return null
+}
+
+twoSum([1, 3, 5, 7, 9], 12) // [1, 4] (3 + 9 = 12)
+```
+
+### Sliding Window - O(n)
+
+Maintain a "window" that slides through the array. Perfect for subarray problems.
+
+```javascript
+// Maximum sum of k consecutive elements
+function maxSumSubarray(arr, k) {
+ if (arr.length < k) return null
+
+ // Calculate first window
+ let windowSum = 0
+ for (let i = 0; i < k; i++) {
+ windowSum += arr[i]
+ }
+
+ let maxSum = windowSum
+
+ // Slide the window: remove left element, add right element
+ for (let i = k; i < arr.length; i++) {
+ windowSum = windowSum - arr[i - k] + arr[i]
+ maxSum = Math.max(maxSum, windowSum)
+ }
+
+ return maxSum
+}
+
+maxSumSubarray([2, 1, 5, 1, 3, 2], 3) // 9 (5 + 1 + 3)
+```
+
+### Frequency Counter - O(n)
+
+Use an object or Map to count occurrences. Avoids nested loops when comparing collections.
+
+```javascript
+// Check if two strings are anagrams
+function isAnagram(str1, str2) {
+ if (str1.length !== str2.length) return false
+
+ const freq = {}
+
+ // Count characters in first string
+ for (const char of str1) {
+ freq[char] = (freq[char] || 0) + 1
+ }
+
+ // Subtract counts for second string
+ for (const char of str2) {
+ if (!freq[char]) return false
+ freq[char]--
+ }
+
+ return true
+}
+
+isAnagram('listen', 'silent') // true
+isAnagram('hello', 'world') // false
+```
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **Big O measures scalability**, not absolute speed. It tells you how performance changes as input grows.
+
+2. **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.
+
+3. **Nested loops multiply complexity**. Two nested loops over n = O(n²). Three = O(n³).
+
+4. **Drop constants and lower terms**. O(2n + 100) simplifies to O(n).
+
+5. **Array end operations are O(1)**, beginning operations are O(n). Prefer `push`/`pop` over `shift`/`unshift`.
+
+6. **Use Set for O(1) lookups** instead of `Array.includes()` for repeated membership checks.
+
+7. **Binary search is O(log n)** but requires sorted data. Worth sorting first if you'll search multiple times.
+
+8. **JavaScript's sort() is O(n log n)** in all modern browsers. Use it unless you have specific requirements.
+
+9. **Learn the patterns**: Two pointers, sliding window, and frequency counter solve most interview problems.
+
+10. **Space complexity matters too**. Creating a new array of size n uses O(n) space.
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ ```javascript
+ function mystery(arr) {
+ for (let i = 0; i < arr.length; i++) {
+ for (let j = 0; j < 10; j++) {
+ console.log(arr[i])
+ }
+ }
+ }
+ ```
+
+ **Answer:** O(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.
+
+
+
+ **Answer:** Because each comparison eliminates half the remaining elements.
+
+ With 1,000 elements: 1000 → 500 → 250 → 125 → 62 → 31 → 15 → 7 → 3 → 1
+
+ That's about 10 steps. log₂(1000) ≈ 10. With 1,000,000 elements, it only takes ~20 steps.
+
+
+
+ **Answer:** It depends on how many lookups you need.
+
+ - **One lookup**: `indexOf()` is faster. O(n) vs O(n) for Set creation + O(1) for lookup.
+ - **Many lookups**: Convert to Set first. O(n) creation + O(1) per lookup beats O(n) per lookup.
+
+ Rule of thumb: If you'll search more than once, use a Set.
+
+
+
+ **Answer:** It's O(n²), making it impractical for large datasets.
+
+ 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.
+
+ Bubble sort is useful for learning but should never be used in production code.
+
+
+
+ **Answer:** Use a Set to track seen elements:
+
+ ```javascript
+ function hasDuplicates(arr) {
+ const seen = new Set()
+ for (const item of arr) {
+ if (seen.has(item)) return true // O(1) lookup
+ seen.add(item) // O(1) insert
+ }
+ return false
+ }
+ ```
+
+ This is O(n) time and O(n) space. The naive nested loop approach would be O(n²) time but O(1) space.
+
+
+
+ **Answer:** **Sliding window** with a Set or Map.
+
+ ```javascript
+ function longestUniqueSubstring(s) {
+ const seen = new Set()
+ let maxLen = 0
+ let left = 0
+
+ for (let right = 0; right < s.length; right++) {
+ while (seen.has(s[right])) {
+ seen.delete(s[left])
+ left++
+ }
+ seen.add(s[right])
+ maxLen = Math.max(maxLen, right - left + 1)
+ }
+
+ return maxLen
+ }
+ ```
+
+ Time: O(n), Space: O(min(n, alphabet size))
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Understanding arrays, objects, Maps, and Sets is essential for choosing the right tool
+
+
+ Many algorithms like merge sort and binary search can be implemented recursively
+
+
+ Map, filter, and reduce are built on these concepts
+
+
+ Understanding the complexity of these common operations
+
+
+
+---
+
+## Reference
+
+
+
+ Complete reference for array methods and their behavior
+
+
+ Hash-based key-value storage with fast lookups
+
+
+ O(1) operations for membership testing
+
+
+
+## Articles
+
+
+
+ Visual reference for time and space complexity of common algorithms and data structures. Bookmark this one.
+
+
+ Comprehensive GitHub repo with 190k+ stars. Every algorithm implemented in JavaScript with explanations.
+
+
+ Detailed breakdown of every array method's complexity with examples and explanations.
+
+
+ FreeCodeCamp's beginner-friendly guide to Big O with real-world analogies.
+
+
+
+## Videos
+
+
+
+ Web Dev Simplified's concise explanation. Perfect if you want the essentials without filler.
+
+
+ Codevolution's complete series covering sorting, searching, and common patterns step by step.
+
+
+ FreeCodeCamp's comprehensive 8-hour course. Great for deep learning when you have the time.
+
+
diff --git a/docs/concepts/async-await.mdx b/docs/concepts/async-await.mdx
new file mode 100644
index 00000000..4b9599d1
--- /dev/null
+++ b/docs/concepts/async-await.mdx
@@ -0,0 +1,1622 @@
+---
+title: "async/await: Writing Async Code That Looks Synchronous in JavaScript"
+sidebarTitle: "async/await: Writing Async Code That Looks Synchronous"
+description: "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."
+---
+
+Why 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?
+
+```javascript
+// This is async code that reads like sync code
+async function getUserData(userId) {
+ const response = await fetch(`/api/users/${userId}`)
+ const user = await response.json()
+ return user
+}
+
+// Using the async function
+(async () => {
+ const user = await getUserData(123)
+ console.log(user.name) // "Alice"
+})()
+```
+
+That'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 ES2017 that makes asynchronous JavaScript look and behave like synchronous code, while still being non-blocking under the hood.
+
+
+**What you'll learn in this guide:**
+- What async/await actually is (and why it's "just" Promises underneath)
+- How the `async` keyword transforms functions into Promise-returning functions
+- How `await` pauses execution without blocking the main thread
+- Error handling with try/catch (finally, a sane way to handle async errors!)
+- The critical difference between sequential and parallel execution
+- The most common async/await mistakes and how to avoid them
+- How async/await relates to the event loop and microtasks
+
+
+
+**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.
+
+
+---
+
+## What is async/await?
+
+Think 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.
+
+Here's the same operation written three ways:
+
+
+
+ ```javascript
+ // Callback hell - nested so deep you need a flashlight
+ function getUserPosts(userId, callback) {
+ fetchUser(userId, (err, user) => {
+ if (err) return callback(err)
+
+ fetchPosts(user.id, (err, posts) => {
+ if (err) return callback(err)
+
+ fetchComments(posts[0].id, (err, comments) => {
+ if (err) return callback(err)
+
+ callback(null, { user, posts, comments })
+ })
+ })
+ })
+ }
+ ```
+
+
+ ```javascript
+ // Promise chains - better, but still nested
+ function getUserPosts(userId) {
+ return fetchUser(userId)
+ .then(user => {
+ return fetchPosts(user.id)
+ .then(posts => {
+ return fetchComments(posts[0].id)
+ .then(comments => ({ user, posts, comments }))
+ })
+ })
+ }
+ ```
+
+
+ ```javascript
+ // async/await - reads like synchronous code!
+ async function getUserPosts(userId) {
+ const user = await fetchUser(userId)
+ const posts = await fetchPosts(user.id)
+ const comments = await fetchComments(posts[0].id)
+ return { user, posts, comments }
+ }
+ ```
+
+
+
+The 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.
+
+
+**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.
+
+
+---
+
+## The Restaurant Analogy
+
+Think of async/await like ordering food at a restaurant with table service versus a fast-food counter.
+
+**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.
+
+**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.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ THE RESTAURANT ANALOGY │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ async function dinner() { │
+│ │
+│ ┌──────────┐ "I'll have the ┌─────────────┐ │
+│ │ YOU │ ──────────────────────► │ KITCHEN │ │
+│ │ (code) │ pasta please" │ (server) │ │
+│ └──────────┘ await order() └─────────────┘ │
+│ │ │ │
+│ │ You're free to do │ Kitchen is │
+│ │ other things while │ preparing... │
+│ │ waiting! │ │
+│ │ │ │
+│ │ "Your pasta!" │ │
+│ ┌──────────┐ ◄────────────────────── ┌─────────────┐ │
+│ │ YOU │ Promise resolved │ KITCHEN │ │
+│ │ resume │ │ done │ │
+│ └──────────┘ └─────────────┘ │
+│ │
+│ return enjoyMeal(pasta) │
+│ } │
+│ │
+│ The KEY: You (the main thread) are NOT blocked while waiting! │
+│ Other customers (other code) can be served. │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+Here'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.
+
+---
+
+## The `async` Keyword
+
+The [`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**.
+
+```javascript
+// Regular function
+function greet() {
+ return 'Hello'
+}
+console.log(greet()) // "Hello"
+
+// Async function - automatically returns a Promise
+async function greetAsync() {
+ return 'Hello'
+}
+console.log(greetAsync()) // Promise {: "Hello"}
+```
+
+### What Happens to Return Values?
+
+When you return a value from an async function, it gets automatically wrapped in `Promise.resolve()`:
+
+```javascript
+async function getValue() {
+ return 42
+}
+
+// The above is equivalent to:
+function getValuePromise() {
+ return Promise.resolve(42)
+}
+
+// Both work the same way:
+getValue().then(value => console.log(value)) // 42
+```
+
+### What Happens When You Throw?
+
+When you throw an error in an async function, it becomes a rejected Promise:
+
+```javascript
+async function failingFunction() {
+ throw new Error('Something went wrong!')
+}
+
+// The above is equivalent to:
+function failingPromise() {
+ return Promise.reject(new Error('Something went wrong!'))
+}
+
+// Both are caught the same way:
+failingFunction().catch(err => console.log(err.message)) // "Something went wrong!"
+```
+
+### Return a Promise? No Double-Wrapping
+
+If you return a Promise from an async function, it doesn't get double-wrapped:
+
+```javascript
+async function fetchData() {
+ // Returning a Promise directly - it's NOT double-wrapped
+ return fetch('/api/data')
+}
+
+// This returns Promise, NOT Promise>
+const response = await fetchData()
+```
+
+### Async Function Expressions and Arrow Functions
+
+You can use `async` with function expressions and arrow functions too:
+
+```javascript
+// Async function expression
+const fetchData = async function() {
+ return await fetch('/api/data')
+}
+
+// Async arrow function
+const loadData = async () => {
+ return await fetch('/api/data')
+}
+
+// Async arrow function (concise body)
+const getData = async () => fetch('/api/data')
+
+// Async method in an object
+const api = {
+ async fetchUser(id) {
+ return await fetch(`/api/users/${id}`)
+ }
+}
+
+// Async method in a class
+class UserService {
+ async getUser(id) {
+ const response = await fetch(`/api/users/${id}`)
+ return response.json()
+ }
+}
+```
+
+
+**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.
+
+
+---
+
+## The `await` Keyword
+
+The [`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.
+
+```javascript
+async function example() {
+ console.log('Before await')
+
+ const result = await somePromise() // Execution pauses here
+
+ console.log('After await:', result) // Resumes when Promise resolves
+}
+```
+
+### Where Can You Use await?
+
+`await` can only be used in two places:
+
+1. **Inside an async function**
+2. **At the top level of an ES module** (top-level await, covered later)
+
+```javascript
+// ✓ Inside async function
+async function fetchUser() {
+ const response = await fetch('/api/user')
+ return response.json()
+}
+
+// ✓ Top-level await in ES modules
+// (in a .mjs file or with "type": "module" in package.json)
+const config = await fetch('/config.json').then(r => r.json())
+
+// ❌ NOT in regular functions
+function regularFunction() {
+ const data = await fetch('/api/data') // SyntaxError!
+}
+
+// ❌ NOT in global scope of scripts (non-modules)
+await fetch('/api/data') // SyntaxError in non-module scripts
+```
+
+### What Can You await?
+
+You can `await` any value, but it's most useful with Promises:
+
+```javascript
+// Awaiting a Promise (the normal case)
+const response = await fetch('/api/data')
+
+// Awaiting Promise.resolve()
+const value = await Promise.resolve(42)
+console.log(value) // 42
+
+// Awaiting a non-Promise value (works, but pointless)
+const num = await 42
+console.log(num) // 42 (immediately, no actual waiting)
+
+// Awaiting a thenable (object with .then method)
+const thenable = {
+ then(resolve) {
+ setTimeout(() => resolve('thenable value'), 1000)
+ }
+}
+const result = await thenable
+console.log(result) // "thenable value" (after 1 second)
+```
+
+
+**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.
+
+
+
+**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.
+
+
+### await Pauses the Function, Not the Thread
+
+This trips people up. `await` pauses only the async function it's in, not the entire JavaScript thread. Other code can run while waiting:
+
+```javascript
+async function slowOperation() {
+ console.log('Starting slow operation')
+ await new Promise(resolve => setTimeout(resolve, 2000))
+ console.log('Slow operation complete')
+}
+
+console.log('Before calling slowOperation')
+slowOperation() // Starts but doesn't block
+console.log('After calling slowOperation')
+
+// Output:
+// "Before calling slowOperation"
+// "Starting slow operation"
+// "After calling slowOperation"
+// (2 seconds later)
+// "Slow operation complete"
+```
+
+Notice that "After calling slowOperation" prints before "Slow operation complete". The main thread wasn't blocked.
+
+---
+
+## How await Works Under the Hood
+
+Let'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.
+
+```javascript
+async function example() {
+ console.log('1. Before await') // Runs synchronously
+ await Promise.resolve()
+ console.log('2. After await') // Runs as a microtask
+}
+
+console.log('A. Before call')
+example()
+console.log('B. After call')
+
+// Output:
+// A. Before call
+// 1. Before await
+// B. After call
+// 2. After await
+```
+
+Let's trace through this step by step:
+
+
+
+ `console.log('A. Before call')` executes → prints "A. Before call"
+
+
+
+ The function starts executing synchronously.
+ `console.log('1. Before await')` executes → prints "1. Before await"
+
+
+
+ `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.
+
+
+
+ `console.log('B. After call')` executes → prints "B. After call"
+
+
+
+ The event loop processes the microtask queue. The continuation of `example()` runs.
+ `console.log('2. After await')` executes → prints "2. After await"
+
+
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ await SPLITS THE FUNCTION │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ async function example() { │
+│ console.log('Before') ──────► Runs SYNCHRONOUSLY │
+│ │
+│ await somePromise() ──────► PAUSE: Schedule continuation │
+│ as microtask, return to caller │
+│ │
+│ console.log('After') ──────► Runs as MICROTASK when │
+│ } Promise resolves │
+│ │
+│ ───────────────────────────────────────────────────────────────────── │
+│ │
+│ Think of it like this - await transforms the function into: │
+│ │
+│ function example() { │
+│ console.log('Before') │
+│ return somePromise().then(() => { │
+│ console.log('After') │
+│ }) │
+│ } │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+
+This 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).
+
+
+---
+
+## Error Handling with try/catch
+
+Finally, 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.
+
+### Basic try/catch Pattern
+
+```javascript
+async function fetchUserData(userId) {
+ try {
+ const response = await fetch(`/api/users/${userId}`)
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! Status: ${response.status}`)
+ }
+
+ const user = await response.json()
+ return user
+
+ } catch (error) {
+ console.error('Failed to fetch user:', error.message)
+ throw error // Re-throw if you want callers to handle it
+ }
+}
+```
+
+### Catching Different Types of Errors
+
+```javascript
+async function processOrder(orderId) {
+ try {
+ const order = await fetchOrder(orderId)
+ const payment = await processPayment(order)
+ const shipment = await createShipment(order)
+ return { order, payment, shipment }
+
+ } catch (error) {
+ // You can check error types
+ if (error.name === 'NetworkError') {
+ console.log('Network issue - please check your connection')
+ } else if (error.name === 'PaymentError') {
+ console.log('Payment failed - please try again')
+ } else {
+ console.log('Unexpected error:', error.message)
+ }
+ throw error
+ }
+}
+```
+
+### The finally Block
+
+The `finally` block always runs, whether the try succeeded or failed:
+
+```javascript
+async function fetchWithLoading(url) {
+ showLoadingSpinner()
+
+ try {
+ const response = await fetch(url)
+ const data = await response.json()
+ return data
+
+ } catch (error) {
+ showErrorMessage(error.message)
+ throw error
+
+ } finally {
+ // This ALWAYS runs - perfect for cleanup
+ hideLoadingSpinner()
+ }
+}
+```
+
+### try/catch vs .catch()
+
+Both approaches work, but they have different use cases:
+
+
+
+ ```javascript
+ // Good for: Multiple awaits where any could fail
+ async function getFullProfile(userId) {
+ try {
+ const user = await fetchUser(userId)
+ const posts = await fetchPosts(userId)
+ const friends = await fetchFriends(userId)
+ return { user, posts, friends }
+ } catch (error) {
+ // Catches any of the three failures
+ console.error('Profile fetch failed:', error)
+ return null
+ }
+ }
+ ```
+
+
+ ```javascript
+ // Good for: Handling errors for specific operations
+ async function getProfileWithFallback(userId) {
+ const user = await fetchUser(userId)
+
+ // Only this operation has fallback behavior
+ const posts = await fetchPosts(userId).catch(() => [])
+
+ // This will still throw if it fails
+ const friends = await fetchFriends(userId)
+
+ return { user, posts, friends }
+ }
+ ```
+
+
+
+### Common Error Handling Mistake
+
+
+**The Trap:** If you catch an error but don't re-throw it, the Promise resolves successfully (with undefined), not rejects!
+
+
+```javascript
+// ❌ WRONG - Error is swallowed, returns undefined
+async function fetchData() {
+ try {
+ const response = await fetch('/api/data')
+ return await response.json()
+ } catch (error) {
+ console.error('Error:', error)
+ // Missing: throw error
+ }
+}
+
+const data = await fetchData() // undefined if there was an error!
+
+// ✓ CORRECT - Re-throw or return a meaningful value
+async function fetchData() {
+ try {
+ const response = await fetch('/api/data')
+ return await response.json()
+ } catch (error) {
+ console.error('Error:', error)
+ throw error // Re-throw to let caller handle it
+ // OR: return null // Return explicit fallback value
+ // OR: return { error: error.message } // Return error object
+ }
+}
+```
+
+---
+
+## Sequential vs Parallel Execution
+
+This is a big one. By default, `await` makes operations sequential, but often you want them to run in parallel.
+
+### The Problem: Unnecessary Sequential Execution
+
+```javascript
+// ❌ SLOW - Each request waits for the previous one
+async function getUserDashboard(userId) {
+ const user = await fetchUser(userId) // Wait ~500ms
+ const posts = await fetchPosts(userId) // Wait ~500ms
+ const notifications = await fetchNotifications(userId) // Wait ~500ms
+
+ return { user, posts, notifications }
+ // Total time: ~1500ms (sequential)
+}
+```
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ SEQUENTIAL EXECUTION (SLOW) │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Time: 0ms 500ms 1000ms 1500ms │
+│ │ │ │ │ │
+│ ├─────────┤ │ │ │
+│ │ user │ │ │ Total: 1500ms │
+│ │ fetch │ │ │ │
+│ └─────────┼─────────┤ │ │
+│ │ posts │ │ │
+│ │ fetch │ │ │
+│ └─────────┼─────────┤ │
+│ │ notifs │ │
+│ │ fetch │ │
+│ └─────────┘ │
+│ │
+│ Each request WAITS for the previous one to complete! │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+### The Solution: Promise.all for Parallel Execution
+
+When operations are independent, run them in parallel:
+
+```javascript
+// ✓ FAST - All requests run simultaneously
+async function getUserDashboard(userId) {
+ const [user, posts, notifications] = await Promise.all([
+ fetchUser(userId), // Starts immediately
+ fetchPosts(userId), // Starts immediately
+ fetchNotifications(userId) // Starts immediately
+ ])
+
+ return { user, posts, notifications }
+ // Total time: ~500ms (parallel - time of slowest request)
+}
+```
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ PARALLEL EXECUTION (FAST) │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Time: 0ms 500ms │
+│ │ │ │
+│ ├─────────┤ │
+│ │ user │ │
+│ │ fetch │ │
+│ ├─────────┤ Total: 500ms (3x faster!) │
+│ │ posts │ │
+│ │ fetch │ │
+│ ├─────────┤ │
+│ │ notifs │ │
+│ │ fetch │ │
+│ └─────────┘ │
+│ │
+│ All requests start at the SAME TIME! │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+### When to Use Sequential vs Parallel
+
+| Use Sequential When | Use Parallel When |
+|---------------------|-------------------|
+| Each operation depends on the previous result | Operations are independent |
+| Order of execution matters | Order doesn't matter |
+| You need to stop on first failure | All results are needed |
+
+### Promise.all vs Promise.allSettled
+
+**[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.
+
+**[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).
+
+```javascript
+// Promise.all - fails fast
+async function getAllOrNothing() {
+ try {
+ const results = await Promise.all([
+ fetchUser(1),
+ fetchUser(999), // This one fails
+ fetchUser(3)
+ ])
+ return results
+ } catch (error) {
+ // If ANY request fails, we end up here
+ console.log('At least one request failed')
+ }
+}
+
+// Promise.allSettled - get all results regardless of failures
+async function getAllResults() {
+ const results = await Promise.allSettled([
+ fetchUser(1),
+ fetchUser(999), // This one fails
+ fetchUser(3)
+ ])
+
+ // results = [
+ // { status: 'fulfilled', value: user1 },
+ // { status: 'rejected', reason: Error },
+ // { status: 'fulfilled', value: user3 }
+ // ]
+
+ const successful = results
+ .filter(r => r.status === 'fulfilled')
+ .map(r => r.value)
+
+ const failed = results
+ .filter(r => r.status === 'rejected')
+ .map(r => r.reason)
+
+ return { successful, failed }
+}
+```
+
+### Mixed Pattern: Some Sequential, Some Parallel
+
+Sometimes you need a mix: some operations depend on others, but independent ones can run in parallel:
+
+```javascript
+async function processOrder(orderId) {
+ // Step 1: Must fetch order first
+ const order = await fetchOrder(orderId)
+
+ // Step 2: These can run in parallel (both depend on order, not each other)
+ const [inventory, pricing] = await Promise.all([
+ checkInventory(order.items),
+ calculatePricing(order.items)
+ ])
+
+ // Step 3: Must wait for both before charging
+ const payment = await processPayment(order, pricing)
+
+ // Step 4: These can run in parallel (both depend on payment)
+ const [receipt, notification] = await Promise.all([
+ generateReceipt(payment),
+ sendConfirmationEmail(order, payment)
+ ])
+
+ return { order, payment, receipt }
+}
+```
+
+---
+
+## The 5 Most Common async/await Mistakes
+
+### Mistake #1: Forgetting await
+
+Without `await`, you get a Promise object instead of the resolved value.
+
+```javascript
+// ❌ WRONG - response is a Promise, not a Response!
+async function fetchUser() {
+ const response = fetch('/api/user') // Missing await!
+ const data = response.json() // Error: response.json is not a function
+ return data
+}
+
+// ✓ CORRECT
+async function fetchUser() {
+ const response = await fetch('/api/user')
+ const data = await response.json()
+ return data
+}
+```
+
+
+**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.
+
+
+### Mistake #2: Using await in forEach
+
+`forEach` and async don't play well together. It just fires and forgets:
+
+```javascript
+// ❌ WRONG - forEach doesn't await!
+async function processUsers(userIds) {
+ userIds.forEach(async (id) => {
+ const user = await fetchUser(id)
+ console.log(user.name)
+ })
+ console.log('Done!') // Prints BEFORE users are fetched!
+}
+
+// ✓ CORRECT - Use for...of for sequential
+async function processUsersSequential(userIds) {
+ for (const id of userIds) {
+ const user = await fetchUser(id)
+ console.log(user.name)
+ }
+ console.log('Done!') // Prints after all users
+}
+
+// ✓ CORRECT - Use Promise.all for parallel
+async function processUsersParallel(userIds) {
+ await Promise.all(
+ userIds.map(async (id) => {
+ const user = await fetchUser(id)
+ console.log(user.name)
+ })
+ )
+ console.log('Done!') // Prints after all users
+}
+```
+
+### Mistake #3: Sequential await When Parallel is Better
+
+We covered this above, but it's worth repeating:
+
+```javascript
+// ❌ SLOW - 3 seconds total
+async function getData() {
+ const a = await fetchA() // 1 second
+ const b = await fetchB() // 1 second
+ const c = await fetchC() // 1 second
+ return { a, b, c }
+}
+
+// ✓ FAST - 1 second total
+async function getData() {
+ const [a, b, c] = await Promise.all([
+ fetchA(),
+ fetchB(),
+ fetchC()
+ ])
+ return { a, b, c }
+}
+```
+
+### Mistake #4: Not Handling Errors
+
+Unhandled Promise rejections can crash your application.
+
+```javascript
+// ❌ WRONG - No error handling
+async function riskyOperation() {
+ const data = await fetch('/api/might-fail')
+ return data.json()
+}
+
+// If fetch fails, we get an unhandled rejection
+riskyOperation() // No .catch(), no try/catch
+
+// ✓ CORRECT - Handle errors
+async function safeOperation() {
+ try {
+ const data = await fetch('/api/might-fail')
+ return data.json()
+ } catch (error) {
+ console.error('Operation failed:', error)
+ return null // Or throw, or return error object
+ }
+}
+
+// Or catch at the call site
+riskyOperation().catch(err => console.error('Failed:', err))
+```
+
+### Mistake #5: Missing await Before return in try/catch
+
+If 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:
+
+```javascript
+// ❌ WRONG - catch block won't catch fetch errors!
+async function fetchData() {
+ try {
+ return fetch('/api/data') // Promise returned before it settles
+ } catch (error) {
+ // This NEVER runs for fetch errors!
+ console.error('Error:', error)
+ }
+}
+
+// ✓ CORRECT - await lets catch block handle errors
+async function fetchData() {
+ try {
+ return await fetch('/api/data') // await IS needed here
+ } catch (error) {
+ console.error('Error:', error)
+ throw error
+ }
+}
+```
+
+**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.
+
+
+**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.
+
+
+```javascript
+// Outside try/catch, these ARE equivalent:
+async function noTryCatch() {
+ return await fetch('/api/data') // await is optional here
+}
+
+async function noTryCatchSimpler() {
+ return fetch('/api/data') // Same result, slightly cleaner
+}
+
+// But inside try/catch, they behave DIFFERENTLY:
+async function withTryCatch() {
+ try {
+ return await fetch('/api/data') // Errors ARE caught
+ } catch (e) { /* handles errors */ }
+}
+
+async function brokenTryCatch() {
+ try {
+ return fetch('/api/data') // Errors NOT caught!
+ } catch (e) { /* never runs for fetch errors */ }
+}
+```
+
+---
+
+## async/await vs Promise Chains
+
+Both async/await and Promise chains achieve the same result. The choice often comes down to readability and personal preference.
+
+### Comparison Table
+
+| Aspect | async/await | Promise Chains |
+|--------|-------------|----------------|
+| **Readability** | Looks like sync code | Nested callbacks |
+| **Error Handling** | try/catch | .catch() |
+| **Debugging** | Better stack traces | Harder to trace |
+| **Conditionals** | Natural if/else | Nested .then() |
+| **Early Returns** | Just use return | Have to throw or nest |
+| **Loops** | for/for...of work naturally | Need recursion or reduce |
+
+### When Promise Chains Might Be Better
+
+```javascript
+// Promise chain is more concise for simple transformations
+fetchUser(id)
+ .then(user => user.profileId)
+ .then(fetchProfile)
+ .then(profile => profile.avatarUrl)
+
+// async/await equivalent - more verbose
+async function getAvatarUrl(id) {
+ const user = await fetchUser(id)
+ const profile = await fetchProfile(user.profileId)
+ return profile.avatarUrl
+}
+
+// Promise.race is cleaner with raw Promises
+const result = await Promise.race([
+ fetch('/api/main'),
+ timeout(5000)
+])
+
+// Promise chain for "fire and forget"
+saveAnalytics(data).catch(console.error) // Don't await, just catch errors
+```
+
+### When async/await Shines
+
+```javascript
+// Complex conditional logic
+async function processOrder(order) {
+ const inventory = await checkInventory(order.items)
+
+ if (!inventory.available) {
+ await notifyBackorder(order)
+ return { status: 'backordered' }
+ }
+
+ const payment = await processPayment(order)
+
+ if (payment.requiresVerification) {
+ await requestVerification(payment)
+ return { status: 'pending_verification' }
+ }
+
+ await shipOrder(order)
+ return { status: 'shipped' }
+}
+
+// Loops with async operations
+async function migrateUsers(users) {
+ for (const user of users) {
+ await migrateUser(user)
+ await delay(100) // Rate limiting
+ }
+}
+
+// Complex error handling
+async function robustFetch(url, retries = 3) {
+ for (let i = 0; i < retries; i++) {
+ try {
+ return await fetch(url)
+ } catch (error) {
+ if (i === retries - 1) throw error
+ await delay(1000 * (i + 1)) // Exponential backoff
+ }
+ }
+}
+```
+
+---
+
+## Top-Level await
+
+[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.
+
+```javascript
+// config.js (ES module)
+const response = await fetch('/config.json')
+export const config = await response.json()
+
+// main.js
+import { config } from './config.js'
+console.log(config) // Config is already loaded!
+```
+
+### Where Top-Level await Works
+
+- **ES Modules** (files with `.mjs` extension or `"type": "module"` in package.json)
+- **Browser `
+```
+
+### Use Cases
+
+```javascript
+// 1. Loading configuration before app starts
+export const config = await loadConfig()
+
+// 2. Dynamic imports
+const module = await import(`./locales/${language}.js`)
+
+// 3. Database connection
+export const db = await connectToDatabase()
+
+// 4. Feature detection
+export const supportsWebGL = await checkWebGLSupport()
+```
+
+
+**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.
+
+
+---
+
+## Advanced Patterns
+
+### Retry with Exponential Backoff
+
+```javascript
+async function fetchWithRetry(url, options = {}) {
+ const { retries = 3, backoff = 1000 } = options
+
+ for (let attempt = 0; attempt < retries; attempt++) {
+ try {
+ const response = await fetch(url)
+
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}`)
+ }
+
+ return response
+
+ } catch (error) {
+ const isLastAttempt = attempt === retries - 1
+
+ if (isLastAttempt) {
+ throw error
+ }
+
+ // Wait with exponential backoff: 1s, 2s, 4s, 8s...
+ const delay = backoff * Math.pow(2, attempt)
+ console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`)
+
+ await new Promise(resolve => setTimeout(resolve, delay))
+ }
+ }
+}
+
+// Usage
+const response = await fetchWithRetry('/api/flaky-endpoint', {
+ retries: 5,
+ backoff: 500
+})
+```
+
+### Timeout Wrapper
+
+```javascript
+async function withTimeout(promise, ms) {
+ const timeout = new Promise((_, reject) => {
+ setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms)
+ })
+
+ return Promise.race([promise, timeout])
+}
+
+// Usage
+try {
+ const response = await withTimeout(fetch('/api/slow'), 5000)
+ console.log('Success:', response)
+} catch (error) {
+ console.log('Failed:', error.message) // "Timeout after 5000ms"
+}
+```
+
+### Cancellation with AbortController
+
+```javascript
+async function fetchWithCancellation(url, signal) {
+ try {
+ const response = await fetch(url, { signal })
+ return await response.json()
+ } catch (error) {
+ if (error.name === 'AbortError') {
+ console.log('Fetch was cancelled')
+ return null
+ }
+ throw error
+ }
+}
+
+// Usage
+const controller = new AbortController()
+
+// Start the fetch
+const dataPromise = fetchWithCancellation('/api/data', controller.signal)
+
+// Cancel after 2 seconds if not done
+setTimeout(() => controller.abort(), 2000)
+
+const data = await dataPromise
+```
+
+### Async Iterators (for await...of)
+
+For working with streams of async data:
+
+```javascript
+async function* generateAsyncNumbers() {
+ for (let i = 1; i <= 5; i++) {
+ await new Promise(resolve => setTimeout(resolve, 1000))
+ yield i
+ }
+}
+
+// Consume the async iterator
+async function processNumbers() {
+ for await (const num of generateAsyncNumbers()) {
+ console.log(num) // Prints 1, 2, 3, 4, 5 (one per second)
+ }
+}
+```
+
+### Converting Callback APIs to async/await
+
+```javascript
+// Original callback-based API
+function readFileCallback(path, callback) {
+ fs.readFile(path, 'utf8', (err, data) => {
+ if (err) callback(err)
+ else callback(null, data)
+ })
+}
+
+// Promisified version
+function readFileAsync(path) {
+ return new Promise((resolve, reject) => {
+ fs.readFile(path, 'utf8', (err, data) => {
+ if (err) reject(err)
+ else resolve(data)
+ })
+ })
+}
+
+// Now you can use async/await
+async function processFile(path) {
+ const content = await readFileAsync(path)
+ return content.toUpperCase()
+}
+
+// Or use util.promisify (Node.js)
+const { promisify } = require('util')
+const readFileAsync = promisify(fs.readFile)
+```
+
+---
+
+## Interview Questions
+
+### Question 1: What's the Output?
+
+```javascript
+async function test() {
+ console.log('1')
+ await Promise.resolve()
+ console.log('2')
+}
+
+console.log('A')
+test()
+console.log('B')
+```
+
+
+**Output:** `A`, `1`, `B`, `2`
+
+**Explanation:**
+1. `console.log('A')` — synchronous → "A"
+2. `test()` is called:
+ - `console.log('1')` — synchronous → "1"
+ - `await Promise.resolve()` — pauses test(), schedules continuation as microtask
+ - Returns to caller
+3. `console.log('B')` — synchronous → "B"
+4. Call stack empty → microtask runs → `console.log('2')` → "2"
+
+The pattern: Code before `await` runs synchronously. Code after `await` becomes a microtask.
+
+
+### Question 2: Sequential vs Parallel
+
+```javascript
+// Version A
+async function versionA() {
+ const start = Date.now()
+ const a = await delay(1000)
+ const b = await delay(1000)
+ console.log(`Time: ${Date.now() - start}ms`)
+}
+
+// Version B
+async function versionB() {
+ const start = Date.now()
+ const [a, b] = await Promise.all([delay(1000), delay(1000)])
+ console.log(`Time: ${Date.now() - start}ms`)
+}
+
+function delay(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms))
+}
+```
+
+
+**versionA:** ~2000ms (sequential — waits 1s, then another 1s)
+
+**versionB:** ~1000ms (parallel — both delays run simultaneously)
+
+This 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.
+
+
+### Question 3: Error Handling
+
+```javascript
+async function outer() {
+ try {
+ await inner()
+ console.log('After inner')
+ } catch (e) {
+ console.log('Caught:', e.message)
+ }
+}
+
+async function inner() {
+ throw new Error('Oops!')
+}
+
+outer()
+```
+
+
+**Output:** `Caught: Oops!`
+
+"After inner" is never printed because `inner()` throws, which causes the `await inner()` to reject, which jumps to the catch block.
+
+This demonstrates that async/await error handling works like synchronous try/catch. Errors "propagate up" naturally.
+
+
+### Question 4: The forEach Trap
+
+```javascript
+async function processItems() {
+ const items = [1, 2, 3]
+
+ items.forEach(async (item) => {
+ await delay(100)
+ console.log(item)
+ })
+
+ console.log('Done')
+}
+
+function delay(ms) {
+ return new Promise(resolve => setTimeout(resolve, ms))
+}
+
+processItems()
+```
+
+
+**Output:**
+```
+Done
+1
+2
+3
+```
+
+(Not `1`, `2`, `3`, `Done` as you might expect!)
+
+**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.
+
+**Fix:** Use `for...of` for sequential or `Promise.all` with `map` for parallel.
+
+
+### Question 5: What's Wrong Here?
+
+```javascript
+async function getData() {
+ try {
+ return fetch('/api/data')
+ } catch (error) {
+ console.error('Failed:', error)
+ return null
+ }
+}
+```
+
+
+**Issue:** The `catch` block will never catch fetch errors.
+
+When 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.
+
+```javascript
+// ❌ WRONG - catch never runs for fetch errors
+async function getData() {
+ try {
+ return fetch('/api/data') // Promise returned immediately
+ } catch (error) {
+ console.error('Failed:', error) // Never runs!
+ return null
+ }
+}
+
+// ✓ CORRECT - await lets catch block handle errors
+async function getData() {
+ try {
+ return await fetch('/api/data') // await IS needed
+ } catch (error) {
+ console.error('Failed:', error) // Now this runs on error
+ return null
+ }
+}
+```
+
+**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.
+
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **async/await is syntactic sugar over Promises** — it doesn't change how async works, just how you write it
+
+2. **async functions always return Promises** — even if you return a plain value, it's wrapped in Promise.resolve()
+
+3. **await pauses the function, not the thread** — other code can run while waiting; JavaScript stays non-blocking
+
+4. **Code after await becomes a microtask** — it runs after the current synchronous code completes, but before setTimeout callbacks
+
+5. **Use try/catch for error handling** — it works just like synchronous code and catches both sync errors and Promise rejections
+
+6. **await in forEach doesn't work as expected** — use for...of for sequential or Promise.all with map for parallel
+
+7. **Prefer parallel over sequential** — use Promise.all when operations are independent; it's often 2-10x faster
+
+8. **Don't forget await** — without it, you get a Promise object instead of the resolved value
+
+9. **Top-level await only works in ES modules** — not in regular scripts or CommonJS
+
+10. **async/await and Promises are interchangeable** — choose based on readability for your specific use case
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ The `async` keyword does two things:
+
+ 1. Makes the function **always return a Promise** — even if you return a non-Promise value, it gets wrapped in `Promise.resolve()`
+ 2. Enables the use of `await` inside the function
+
+ ```javascript
+ async function example() {
+ return 42
+ }
+
+ example().then(value => console.log(value)) // 42
+ console.log(example()) // Promise {: 42}
+ ```
+
+
+
+ ```javascript
+ // Version A
+ const data = await fetchData()
+
+ // Version B
+ const data = fetchData()
+ ```
+
+ **Answer:**
+
+ - **Version A:** `data` contains the resolved value (e.g., the actual JSON object)
+ - **Version B:** `data` contains a Promise object, not the resolved value
+
+ Version B is a common mistake that leads to bugs like seeing `[object Promise]` or getting undefined properties.
+
+
+
+ **Answer:**
+
+ Use `Promise.all()` to run multiple async operations simultaneously:
+
+ ```javascript
+ // ❌ Sequential (slow)
+ const a = await fetchA()
+ const b = await fetchB()
+ const c = await fetchC()
+
+ // ✓ Parallel (fast)
+ const [a, b, c] = await Promise.all([
+ fetchA(),
+ fetchB(),
+ fetchC()
+ ])
+ ```
+
+ For cases where you want all results even if some fail, use `Promise.allSettled()`.
+
+
+
+ **Answer:**
+
+ `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.
+
+ ```javascript
+ // ❌ Doesn't wait
+ items.forEach(async item => {
+ await processItem(item)
+ })
+ console.log('Done') // Prints before items are processed!
+
+ // ✓ Sequential - use for...of
+ for (const item of items) {
+ await processItem(item)
+ }
+ console.log('Done') // Prints after all items
+
+ // ✓ Parallel - use Promise.all with map
+ await Promise.all(items.map(item => processItem(item)))
+ console.log('Done') // Prints after all items
+ ```
+
+
+
+ **Answer:**
+
+ Use `try/catch` blocks, which work just like synchronous error handling:
+
+ ```javascript
+ async function fetchData() {
+ try {
+ const response = await fetch('/api/data')
+ if (!response.ok) {
+ throw new Error(`HTTP ${response.status}`)
+ }
+ return await response.json()
+ } catch (error) {
+ console.error('Fetch failed:', error)
+ throw error // Re-throw if caller should handle it
+ } finally {
+ // Cleanup code that always runs
+ }
+ }
+ ```
+
+ You can also use `.catch()` at the call site: `fetchData().catch(handleError)`
+
+
+
+ ```javascript
+ console.log('1')
+ setTimeout(() => console.log('2'), 0)
+ Promise.resolve().then(() => console.log('3'))
+ async function test() {
+ console.log('4')
+ await Promise.resolve()
+ console.log('5')
+ }
+ test()
+ console.log('6')
+ ```
+
+ **Answer:** `1`, `4`, `6`, `3`, `5`, `2`
+
+ **Explanation:**
+ 1. `'1'` — synchronous
+ 2. `setTimeout` callback → task queue
+ 3. `.then` callback → microtask queue
+ 4. `test()` called → `'4'` — synchronous part of async function
+ 5. `await` → schedules `'5'` as microtask, returns to caller
+ 6. `'6'` — synchronous
+ 7. Call stack empty → process microtasks: `'3'` then `'5'`
+ 8. Microtasks done → process task queue: `'2'`
+
+ Key: Microtasks (Promises, await continuations) run before macrotasks (setTimeout).
+
+
+
+---
+
+## Related Concepts
+
+
+
+ async/await is built on Promises. Knowing Promises well makes async/await easier
+
+
+ Learn how JavaScript handles async operations and why await creates microtasks
+
+
+ The original async pattern that async/await replaced
+
+
+ The most common use case for async/await: making HTTP requests
+
+
+
+---
+
+## Reference
+
+
+
+ Complete reference for async function declarations and expressions
+
+
+ Documentation for the await operator and its behavior
+
+
+ The foundation that async/await is built on
+
+
+ Error handling syntax used with async/await
+
+
+
+## Articles
+
+
+
+ The go-to reference for async/await fundamentals. Includes exercises at the end to test your understanding of rewriting promise chains.
+
+
+ Learn async patterns by building a virtual ice cream shop. The GIFs comparing sync vs async execution are worth the visit alone.
+
+
+
+ Side-by-side code comparisons that show exactly how async/await cleans up promise chains. The debugging section alone is worth bookmarking.
+
+
+ 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.
+
+
+ The pizza-and-drinks ordering example makes parallel vs sequential execution crystal clear. Essential reading once you know the basics.
+
+
+
+## Videos
+
+
+
+ Web Dev Simplified breaks down async/await in 12 minutes. Perfect if you learn better from watching code being written live.
+
+
+ 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.
+
+
+ Traversy Media's full async journey from callbacks through promises to async/await. Great if you want to see how we got here historically.
+
+
+ Hitesh Choudhary's hands-on walkthrough with coding examples. Hindi and English explanations make concepts accessible to a wider audience.
+
+
diff --git a/docs/concepts/call-stack.mdx b/docs/concepts/call-stack.mdx
new file mode 100644
index 00000000..0cf70308
--- /dev/null
+++ b/docs/concepts/call-stack.mdx
@@ -0,0 +1,998 @@
+---
+title: "Call Stack: How Function Execution Works in JavaScript"
+sidebarTitle: "Call Stack: How Function Execution Works"
+description: "Learn how the JavaScript call stack tracks function execution. Understand stack frames, LIFO ordering, execution contexts, stack overflow errors, and debugging with stack traces."
+---
+
+How 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?
+
+The answer is the **[call stack](https://developer.mozilla.org/en-US/docs/Glossary/Call_stack)**. It's JavaScript's mechanism for tracking function execution.
+
+```javascript
+function greet(name) {
+ const message = createMessage(name)
+ console.log(message)
+}
+
+function createMessage(name) {
+ return "Hello, " + name + "!"
+}
+
+greet("Alice") // "Hello, Alice!"
+```
+
+When `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.
+
+
+**What you'll learn in this guide:**
+- What the call stack is and why JavaScript needs it
+- How functions are added and removed from the stack
+- What happens step-by-step when your code runs
+- Why you sometimes see "Maximum call stack size exceeded" errors
+- How to debug call stack issues like a pro
+
+
+
+**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!
+
+
+---
+
+## The Stack of Plates: A Real-World Analogy
+
+Imagine 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.
+
+```
+ ┌───────────┐
+ │ Plate 3 │ ← You add here (top)
+ ├───────────┤
+ │ Plate 2 │
+ ├───────────┤
+ │ Plate 1 │ ← First plate (bottom)
+ └───────────┘
+```
+
+This 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.
+
+This simple concept, **adding to the top and removing from the top**, is the foundation of how JavaScript executes your code.
+
+---
+
+## What is the Call Stack?
+
+The **[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.
+
+```javascript
+function first() { second(); }
+function second() { third(); }
+function third() { console.log('Hello!'); }
+
+first();
+// Stack grows: [first] → [second, first] → [third, second, first]
+// Stack shrinks: [second, first] → [first] → []
+```
+
+### The LIFO Principle
+
+The call stack follows a principle called **LIFO**: **Last In, First Out**.
+
+- **Last In**: The most recent function call goes on top
+- **First Out**: The function on top must finish before we can get to the ones below
+
+```
+LIFO = Last In, First Out
+
+┌─────────────────┐
+│ function C │ ← Last in (most recent call)
+├─────────────────┤ First to finish and leave
+│ function B │
+├─────────────────┤
+│ function A │ ← First in (earliest call)
+└─────────────────┘ Last to finish
+```
+
+### Why Does JavaScript Need a Call Stack?
+
+JavaScript is **[single-threaded](https://developer.mozilla.org/en-US/docs/Glossary/Thread)**, meaning it can only do **one thing at a time**. The call stack helps JavaScript:
+
+1. **Remember where it is** — Which function is currently running?
+2. **Know where to go back** — When a function finishes, where should execution continue?
+3. **Keep track of local variables** — Each function has its own variables that shouldn't interfere with others
+
+
+**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.
+
+
+---
+
+## How the Call Stack Works: Step-by-Step
+
+Let's trace through a simple example to see the call stack in action.
+
+### A Simple Example
+
+```javascript
+function greet(name) {
+ const greeting = createGreeting(name);
+ console.log(greeting);
+}
+
+function createGreeting(name) {
+ return "Hello, " + name + "!";
+}
+
+// Start here
+greet("Alice");
+console.log("Done!");
+```
+
+### Step-by-Step Execution
+
+
+
+ JavaScript begins executing your code from top to bottom. The call stack is empty.
+
+ ```
+ Call Stack: [ empty ]
+ ```
+
+
+
+ JavaScript sees `greet("Alice")` and pushes `greet` onto the call stack.
+
+ ```
+ Call Stack: [ greet ]
+ ```
+
+ Now JavaScript enters the `greet` function and starts executing its code.
+
+
+
+ Inside `greet`, JavaScript encounters `createGreeting(name)`. It pushes `createGreeting` onto the stack.
+
+ ```
+ Call Stack: [ createGreeting, greet ]
+ ```
+
+ Notice: `greet` is **paused** while `createGreeting` runs. JavaScript can only do one thing at a time!
+
+
+
+ `createGreeting` finishes and returns `"Hello, Alice!"`. JavaScript pops it off the stack.
+
+ ```
+ Call Stack: [ greet ]
+ ```
+
+ The return value (`"Hello, Alice!"`) is passed back to `greet`.
+
+
+
+ Back in `greet`, the returned value is stored in `greeting`, then `console.log` runs. Finally, `greet` finishes and is popped off.
+
+ ```
+ Call Stack: [ empty ]
+ ```
+
+
+
+ With the stack empty, JavaScript continues to the next line: `console.log("Done!")`.
+
+ **Output:**
+ ```
+ Hello, Alice!
+ Done!
+ ```
+
+
+
+### Visual Summary
+
+
+
+ ```
+ Step 1: Step 2: Step 3: Step 4: Step 5:
+
+ ┌─────────┐ ┌─────────┐ ┌────────────────┐ ┌─────────┐ ┌─────────┐
+ │ (empty) │ → │ greet │ → │createGreeting │ → │ greet │ → │ (empty) │
+ └─────────┘ └─────────┘ ├────────────────┤ └─────────┘ └─────────┘
+ │ greet │
+ └────────────────┘
+
+ Program greet() createGreeting() createGreeting greet()
+ starts called called returns returns
+ ```
+
+
+ | Step | Action | Stack (top → bottom) | What's Happening |
+ |------|--------|---------------------|------------------|
+ | 1 | Start | `[]` | Program begins |
+ | 2 | Call `greet("Alice")` | `[greet]` | Enter greet function |
+ | 3 | Call `createGreeting("Alice")` | `[createGreeting, greet]` | greet pauses, enter createGreeting |
+ | 4 | Return from createGreeting | `[greet]` | createGreeting done, back to greet |
+ | 5 | Return from greet | `[]` | greet done, continue program |
+ | 6 | `console.log("Done!")` | `[]` | Print "Done!" |
+
+
+
+---
+
+## Execution Context: What's Actually on the Stack?
+
+When 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.
+
+
+
+ The values passed to the function when it was called.
+
+ ```javascript
+ function greet(name, age) {
+ // Arguments: { name: "Alice", age: 25 }
+ }
+ greet("Alice", 25);
+ ```
+
+
+
+ Variables declared inside the function with `var`, `let`, or `const`.
+
+ ```javascript
+ function calculate() {
+ const x = 10; // Local variable
+ let y = 20; // Local variable
+ var z = 30; // Local variable
+ // These only exist inside this function
+ }
+ ```
+
+
+
+ The value of `this` inside the function, which depends on how the function was called.
+
+ ```javascript
+ const person = {
+ name: "Alice",
+ greet() {
+ console.log(this.name); // 'this' refers to person
+ }
+ };
+ ```
+
+
+
+ Where JavaScript should continue executing after this function returns. This is how JavaScript knows to go back to the right place in your code.
+
+
+
+ Access to variables from outer (parent) functions. This is how closures work!
+
+ ```javascript
+ function outer() {
+ const message = "Hello";
+
+ function inner() {
+ console.log(message); // Can access 'message' from outer
+ }
+
+ inner();
+ }
+ ```
+
+
+
+### Visualizing an Execution Context
+
+```
+┌─────────────────────────────────────────┐
+│ EXECUTION CONTEXT │
+│ Function: greet │
+├─────────────────────────────────────────┤
+│ Arguments: { name: "Alice" } │
+│ Local Vars: { greeting: undefined } │
+│ this: window (or undefined) │
+│ Return to: line 12, main program │
+│ Outer Scope: [global scope] │
+└─────────────────────────────────────────┘
+```
+
+---
+
+## Nested Function Calls: A Deeper Example
+
+Let's look at a more complex example with multiple levels of function calls.
+
+```javascript
+function multiply(x, y) {
+ return x * y;
+}
+
+function square(n) {
+ return multiply(n, n);
+}
+
+function printSquare(n) {
+ const result = square(n);
+ console.log(result);
+}
+
+printSquare(4);
+```
+
+### Tracing the Execution
+
+
+
+ **Step 1: Call printSquare(4)**
+ ```
+ Stack: [ printSquare ]
+ ```
+
+ **Step 2: printSquare calls square(4)**
+ ```
+ Stack: [ square, printSquare ]
+ ```
+
+ **Step 3: square calls multiply(4, 4)**
+ ```
+ Stack: [ multiply, square, printSquare ]
+ ```
+ This is the **maximum stack depth** for this program: 3 frames.
+
+ **Step 4: multiply returns 16**
+ ```
+ Stack: [ square, printSquare ]
+ ```
+
+ **Step 5: square returns 16**
+ ```
+ Stack: [ printSquare ]
+ ```
+
+ **Step 6: printSquare logs 16 and returns**
+ ```
+ Stack: [ empty ]
+ ```
+
+ **Output: `16`**
+
+
+ ```
+ printSquare(4) square(4) multiply(4,4) multiply square printSquare
+ called called called returns 16 returns 16 returns
+
+ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────┐
+ │printSquare │ → │ square │ → │ multiply │ → │ square │ → │printSquare │ → │ (empty) │
+ └─────────────┘ ├─────────────┤ ├─────────────┤ ├─────────────┤ └─────────────┘ └─────────┘
+ │printSquare │ │ square │ │printSquare │
+ └─────────────┘ ├─────────────┤ └─────────────┘
+ │printSquare │
+ └─────────────┘
+
+ Depth: 1 Depth: 2 Depth: 3 Depth: 2 Depth: 1 Depth: 0
+ ```
+
+
+
+
+**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`.
+
+
+---
+
+## The #1 Call Stack Mistake: Stack Overflow
+
+The call stack has a **limited size**. 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.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ STACK OVERFLOW │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ WRONG: No Base Case RIGHT: With Base Case │
+│ ──────────────────── ───────────────────── │
+│ │
+│ function count() { function count(n) { │
+│ count() // Forever! if (n <= 0) return // Stop! │
+│ } count(n - 1) │
+│ } │
+│ │
+│ Stack grows forever... Stack grows, then shrinks │
+│ ┌─────────┐ ┌─────────┐ │
+│ │ count() │ │ count(0)│ ← Returns │
+│ ├─────────┤ ├─────────┤ │
+│ │ count() │ │ count(1)│ │
+│ ├─────────┤ ├─────────┤ │
+│ │ count() │ │ count(2)│ │
+│ ├─────────┤ └─────────┘ │
+│ │ .... │ │
+│ └─────────┘ │
+│ 💥 CRASH! ✓ Success! │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+
+**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.
+
+
+### The Classic Mistake: Missing Base Case
+
+```javascript
+// ❌ BAD: This will crash!
+function countdown(n) {
+ console.log(n);
+ countdown(n - 1); // Calls itself forever!
+}
+
+countdown(5);
+```
+
+**What happens:**
+```
+Stack: [ countdown(5) ]
+Stack: [ countdown(4), countdown(5) ]
+Stack: [ countdown(3), countdown(4), countdown(5) ]
+Stack: [ countdown(2), countdown(3), countdown(4), countdown(5) ]
+... keeps growing forever ...
+💥 CRASH: Maximum call stack size exceeded
+```
+
+### The Fix: Add a Base Case
+
+```javascript
+// ✅ GOOD: This works correctly
+function countdown(n) {
+ if (n <= 0) {
+ console.log("Done!");
+ return; // ← BASE CASE: Stop here!
+ }
+ console.log(n);
+ countdown(n - 1);
+}
+
+countdown(5);
+// Output: 5, 4, 3, 2, 1, Done!
+```
+
+**What happens now:**
+```
+Stack: [ countdown(5) ]
+Stack: [ countdown(4), countdown(5) ]
+Stack: [ countdown(3), countdown(4), countdown(5) ]
+Stack: [ countdown(2), countdown(3), ..., countdown(5) ]
+Stack: [ countdown(1), countdown(2), ..., countdown(5) ]
+Stack: [ countdown(0), countdown(1), ..., countdown(5) ]
+ ↑ Base case reached! Start returning.
+Stack: [ countdown(1), ..., countdown(5) ]
+Stack: [ countdown(2), ..., countdown(5) ]
+... stack unwinds ...
+Stack: [ countdown(5) ]
+Stack: [ empty ]
+✅ Program completes successfully
+```
+
+### Error Messages by Browser
+
+| Browser | Error Message |
+|---------|---------------|
+| Chrome | `RangeError: Maximum call stack size exceeded` |
+| Firefox | `InternalError: too much recursion` (non-standard) |
+| Safari | `RangeError: Maximum call stack size exceeded` |
+
+
+Firefox uses `InternalError` which is a non-standard error type specific to the SpiderMonkey engine. Chrome and Safari use the standard `RangeError`.
+
+
+### Common Causes of Stack Overflow
+
+
+
+ ```javascript
+ // Missing the stopping condition
+ function loop() {
+ loop();
+ }
+ loop(); // 💥 Crash!
+ ```
+
+
+
+ ```javascript
+ function countUp(n) {
+ if (n >= 1000000000000) return; // Too far away!
+ countUp(n + 1);
+ }
+ countUp(0); // 💥 Crash before reaching base case
+ ```
+
+
+
+ ```javascript
+ class Person {
+ set name(value) {
+ this.name = value; // Calls the setter again! Infinite loop!
+ }
+ }
+
+ const p = new Person();
+ p.name = "Alice"; // 💥 Crash!
+
+ // Fix: Use a different property name
+ class PersonFixed {
+ set name(value) {
+ this._name = value; // Use _name instead
+ }
+ }
+ ```
+
+
+
+ ```javascript
+ function a() { b(); }
+ function b() { a(); } // a calls b, b calls a, forever!
+
+ a(); // 💥 Crash!
+ ```
+
+
+
+
+**Prevention tips:**
+1. Always define a clear **base case** for recursive functions
+2. Make sure each recursive call moves **toward** the base case
+3. Consider using **iteration** (loops) instead of recursion for simple cases
+4. Be careful with property setters, use different internal property names
+
+
+---
+
+## Debugging the Call Stack
+
+When something goes wrong, the call stack is your best friend for figuring out what happened.
+
+### Reading a Stack Trace
+
+When 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.
+
+```javascript
+function a() { b(); }
+function b() { c(); }
+function c() {
+ throw new Error('Something went wrong!');
+}
+
+a();
+```
+
+**Output:**
+```
+Error: Something went wrong!
+ at c (script.js:4:9)
+ at b (script.js:2:14)
+ at a (script.js:1:14)
+ at script.js:7:1
+```
+
+**How to read it:**
+- Read from **top to bottom** = most recent call to oldest
+- `at c (script.js:4:9)` = Error occurred in function `c`, file `script.js`, line 4, column 9
+- The trace shows you exactly how the program got to the error
+
+### Using Browser DevTools
+
+
+
+ Press `F12` or `Cmd+Option+I` (Mac) / `Ctrl+Shift+I` (Windows)
+
+
+
+ Click on the "Sources" tab (Chrome) or "Debugger" tab (Firefox)
+
+
+
+ Click on a line number in your code to set a breakpoint. Execution will pause there.
+
+
+
+ When paused, look at the "Call Stack" panel on the right. It shows all the functions currently on the stack.
+
+
+
+ Use the step buttons to execute one line at a time and watch the stack change.
+
+
+
+
+**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:
+
+```javascript
+function factorial(n) {
+ console.log('factorial called with n =', n);
+ if (n <= 1) return 1;
+ return n * factorial(n - 1);
+}
+```
+
+
+---
+
+## The Call Stack and Asynchronous Code
+
+You 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?"
+
+Great question! The call stack is only **part** of the picture.
+
+
+When 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**.
+
+This is covered in detail in the [Event Loop](/concepts/event-loop) section.
+
+
+Here's a sneak peek:
+
+```javascript
+console.log('First');
+
+setTimeout(() => {
+ console.log('Second');
+}, 0);
+
+console.log('Third');
+
+// Output:
+// First
+// Third
+// Second ← Even with 0ms delay, this runs last!
+```
+
+The `setTimeout` callback doesn't go directly on the call stack. It waits in a queue until the stack is empty. This is why "Third" prints before "Second" even though the timeout is 0 milliseconds.
+
+
+
+ Learn how JavaScript handles asynchronous operations
+
+
+ Modern way to handle async code
+
+
+
+---
+
+## Common Misconceptions
+
+
+
+ **Wrong!** The call stack and heap are completely different structures:
+
+ | Component | Purpose | Structure |
+ |-----------|---------|-----------|
+ | **Call Stack** | Tracks function execution | Ordered (LIFO), small, fast |
+ | **Heap** | Stores data (objects, arrays) | Unstructured, large |
+
+ ```javascript
+ function example() {
+ // Primitives live in the stack frame
+ const x = 10;
+ const name = "Alice";
+
+ // Objects live in the HEAP (reference stored in stack)
+ const user = { name: "Alice" };
+ const numbers = [1, 2, 3];
+ }
+ ```
+
+ When the function returns, the stack frame is popped (primitives gone), but heap objects persist until garbage collected.
+
+
+
+ **Wrong!** When a timer finishes, the callback does NOT run immediately. It goes to the **Task Queue** and must wait for:
+
+ 1. The call stack to be completely empty
+ 2. All microtasks to be processed first
+ 3. Its turn in the task queue
+
+ ```javascript
+ console.log('Start');
+
+ setTimeout(() => {
+ console.log('Timer'); // Does NOT run at 0ms!
+ }, 0);
+
+ console.log('End');
+
+ // Output: Start, End, Timer
+ // Even with 0ms delay, 'Timer' prints LAST
+ ```
+
+ The callback must wait until the current script finishes and the stack is empty.
+
+
+
+ **Wrong!** JavaScript is **single-threaded**. It has ONE call stack and can only execute ONE thing at a time.
+
+ ```javascript
+ function a() {
+ console.log('A start');
+ b(); // JS pauses 'a' and runs 'b' completely
+ console.log('A end');
+ }
+
+ function b() {
+ console.log('B');
+ }
+
+ a();
+ // Output: A start, B, A end (sequential, not parallel)
+ ```
+
+ **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.
+
+
+
+ **Wrong!** The Promise *constructor* runs **synchronously**. Only the `.then()` callbacks are asynchronous:
+
+ ```javascript
+ console.log('1');
+
+ new Promise((resolve) => {
+ console.log('2'); // Runs SYNCHRONOUSLY!
+ resolve();
+ }).then(() => {
+ console.log('3'); // Async (microtask)
+ });
+
+ console.log('4');
+
+ // Output: 1, 2, 4, 3
+ // Note: '2' prints before '4'!
+ ```
+
+ The executor function passed to `new Promise()` runs immediately on the call stack. Only the `.then()`, `.catch()`, and `.finally()` callbacks are queued as microtasks.
+
+
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember about the Call Stack:**
+
+1. **JavaScript is single-threaded** — It has ONE call stack and can only do one thing at a time
+
+2. **LIFO principle** — Last In, First Out. The most recent function call finishes first
+
+3. **Execution contexts** — Each function call creates a "frame" containing arguments, local variables, and return address
+
+4. **Synchronous execution** — Functions must complete before their callers can continue
+
+5. **Stack overflow** — Happens when the stack gets too deep, usually from infinite recursion
+
+6. **Always have a base case** — Recursive functions need a stopping condition
+
+7. **Stack traces are your friend** — They show you exactly how your program got to an error
+
+8. **Async callbacks wait** — `setTimeout`, `fetch`, and event callbacks don't run until the call stack is empty
+
+9. **Each frame is isolated** — Local variables in one function call don't affect variables in another call of the same function
+
+10. **Debugging tools show the stack** — Browser DevTools let you pause execution and inspect the current call stack
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:** LIFO stands for **Last In, First Out**.
+
+ 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.
+
+
+
+ ```javascript
+ function a() { b(); }
+ function b() { c(); }
+ function c() { d(); }
+ function d() { console.log('done'); }
+ a();
+ ```
+
+ **Answer:** The maximum stack depth is **4 frames**.
+
+ ```
+ Stack at deepest point: [ d, c, b, a ]
+ ```
+
+ When `d()` is executing, all four functions are on the stack. After `d()` logs "done" and returns, the stack starts unwinding.
+
+
+
+ ```javascript
+ function greet() {
+ greet();
+ }
+ greet();
+ ```
+
+ **Answer:** This code causes a stack overflow because there's **no base case** to stop the recursion.
+
+ - `greet()` is called
+ - `greet()` calls `greet()` again
+ - That `greet()` calls `greet()` again
+ - This continues forever, adding new frames to the stack
+ - Eventually the stack runs out of space → **Maximum call stack size exceeded**
+
+ **Fix:** Add a condition to stop the recursion:
+ ```javascript
+ function greet(times) {
+ if (times <= 0) return; // Base case
+ console.log('Hello!');
+ greet(times - 1);
+ }
+ greet(3);
+ ```
+
+
+
+ **Answer:** An execution context (stack frame) contains:
+
+ 1. **Function arguments** — The values passed to the function
+ 2. **Local variables** — Variables declared with `var`, `let`, or `const`
+ 3. **The `this` value** — The context binding for the function
+ 4. **Return address** — Where to continue executing after the function returns
+ 5. **Scope chain** — Access to variables from outer (parent) functions
+
+ This is why each function call can have its own independent set of variables without interfering with other calls.
+
+
+
+ ```javascript
+ console.log('First')
+
+ setTimeout(() => {
+ console.log('Second')
+ }, 0)
+
+ console.log('Third')
+ ```
+
+ **Answer:** The output is:
+ ```
+ First
+ Third
+ Second
+ ```
+
+ Even though `setTimeout` has a 0ms delay, "Second" prints last because:
+
+ 1. `setTimeout` doesn't put the callback directly on the call stack
+ 2. Instead, the callback waits in the **task queue**
+ 3. The event loop only moves it to the call stack when the stack is empty
+ 4. "Third" runs first because it's already on the call stack
+
+ This demonstrates that the call stack must be empty before async callbacks execute.
+
+
+
+ Given this error:
+ ```
+ Error: Something went wrong!
+ at c (script.js:4:9)
+ at b (script.js:2:14)
+ at a (script.js:1:14)
+ at script.js:7:1
+ ```
+
+ **Answer:** Read stack traces from **top to bottom** (most recent to oldest):
+
+ 1. **Top line** (`at c`) — Where the error actually occurred (function `c`, line 4, column 9)
+ 2. **Following lines** — The chain of function calls that led here
+ 3. **Bottom line** — Where the chain started (the initial call)
+
+ 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.
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Understanding how primitives are stored in stack frames
+
+
+ Understanding variable visibility and how functions remember their environment
+
+
+ How async code works with the call stack
+
+
+ Functions that call themselves
+
+
+
+---
+
+## Reference
+
+
+
+ Official MDN documentation on the Call Stack
+
+
+ How the event loop interacts with the call stack
+
+
+ The error thrown when the call stack overflows
+
+
+ How to read and use stack traces for debugging
+
+
+
+## Articles
+
+
+
+ The complete picture: how the Call Stack, Heap, Event Loop, and Web APIs work together. Great starting point for understanding JavaScript's runtime.
+
+
+ Beginner-friendly freeCodeCamp tutorial covering LIFO, stack traces, and stack overflow with clear code examples.
+
+
+ Go deeper into how the JS engine creates execution contexts and manages the Global Memory. Perfect for interview prep.
+
+
+ Beautiful ASCII art visualization showing step-by-step how setTimeout interacts with the Call Stack and Event Loop.
+
+
+ Advanced deep-dive into Creation vs Execution phases, Lexical Environment, and why `let`/`const` behave differently than `var`.
+
+
+ Explore the JS Engine architecture: V8, memory heap, and call stack from a systems perspective.
+
+
+
+## Courses
+
+
+ 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.
+
+
+## Videos
+
+
+
+ 🏆 The legendary JSConf talk that made mass developers finally "get" the event loop. Amazing visualizations — a must watch!
+
+
+ Short, sweet, and beginner-friendly. Colt Steele breaks down the call stack with practical examples.
+
+
+ Part of the popular "Namaste JavaScript" series. Akshay Saini explains execution with great visuals and examples.
+
+
+ Shows how JavaScript creates execution contexts and manages memory during function calls. Part of Codesmith's excellent "JavaScript: The Hard Parts" series.
+
+
+ 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.
+
+
+ Uses a simple factorial example to demonstrate recursion on the call stack. Under 10 minutes, perfect for a quick refresher.
+
+
+ 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.
+
+
+ Harvard's CS50 explains call stacks from a computer science perspective — great for understanding the theory.
+
+
+ Live codes examples while explaining each concept, so you see exactly how to trace execution yourself. Great for following along in your own editor.
+
+
+ Focuses on the relationship between function invocation and stack frames. Explains why understanding the call stack helps you debug errors faster.
+
+
diff --git a/docs/concepts/callbacks.mdx b/docs/concepts/callbacks.mdx
new file mode 100644
index 00000000..bd61a787
--- /dev/null
+++ b/docs/concepts/callbacks.mdx
@@ -0,0 +1,1439 @@
+---
+title: "Callbacks: The Foundation of Async JavaScript"
+sidebarTitle: "Callbacks: The Foundation of Async"
+description: "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."
+---
+
+Why 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?
+
+```javascript
+console.log('Before timer')
+
+setTimeout(function() {
+ console.log('Timer fired!')
+}, 1000)
+
+console.log('After timer')
+
+// Output:
+// Before timer
+// After timer
+// Timer fired! (1 second later)
+```
+
+The answer is **callbacks**: functions you pass to other functions, saying "call me back when you're done." Callbacks power everything async in JavaScript. Every event handler, every timer, every network request. They all rely on them.
+
+
+**What you'll learn in this guide:**
+- What callbacks are and why JavaScript uses them
+- The difference between synchronous and asynchronous callbacks
+- How callbacks connect to higher-order functions
+- Common callback patterns (event handlers, timers, array methods)
+- The error-first callback pattern (Node.js convention)
+- Callback hell and the "pyramid of doom"
+- How to escape callback hell
+- Why Promises were invented to solve callback problems
+
+
+
+**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.
+
+
+---
+
+## What is a Callback?
+
+A **[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.
+
+```javascript
+// greet is a callback function
+function greet(name) {
+ console.log(`Hello, ${name}!`)
+}
+
+// processUserInput accepts a callback
+function processUserInput(callback) {
+ const name = 'Alice'
+ callback(name) // "calling back" the function we received
+}
+
+processUserInput(greet) // "Hello, Alice!"
+```
+
+The 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."
+
+
+**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.
+
+
+### Callbacks Can Be Anonymous
+
+You don't have to define callbacks as named functions. Anonymous functions (and arrow functions) work just as well:
+
+```javascript
+// Named function as callback
+function handleClick() {
+ console.log('Clicked!')
+}
+button.addEventListener('click', handleClick)
+
+// Anonymous function as callback
+button.addEventListener('click', function() {
+ console.log('Clicked!')
+})
+
+// Arrow function as callback
+button.addEventListener('click', () => {
+ console.log('Clicked!')
+})
+```
+
+All three do the same thing. Named functions are easier to debug though, and you can reuse them.
+
+---
+
+## The Restaurant Buzzer Analogy
+
+Callbacks work like the buzzer you get at a busy restaurant:
+
+1. **You place an order** — You call a function and pass it a callback
+2. **You get a buzzer** — The function registers your callback
+3. **You go sit down** — Your code continues running (non-blocking)
+4. **The buzzer goes off** — The async operation completes
+5. **You pick up your food** — Your callback is executed
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ THE RESTAURANT BUZZER ANALOGY │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ YOU (Your Code) RESTAURANT (JavaScript Runtime) │
+│ │
+│ ┌──────────────┐ ┌─────────────────────────────────┐ │
+│ │ │ │ KITCHEN │ │
+│ │ "I'd like │ ────────► │ (Web APIs) │ │
+│ │ a burger" │ ORDER │ │ │
+│ │ │ │ [setTimeout: 5 min] │ │
+│ └──────────────┘ │ [fetch: waiting...] │ │
+│ │ │ [click: listening...] │ │
+│ │ └─────────────────────────────────┘ │
+│ │ │ │
+│ │ You get a buzzer │ When ready... │
+│ │ and go sit down ▼ │
+│ │ ┌─────────────────────────────────┐ │
+│ │ │ PICKUP COUNTER │ │
+│ ▼ │ (Callback Queue) │ │
+│ ┌──────────────┐ │ │ │
+│ │ │ │ [Your callback waiting here] │ │
+│ │ 📱 BUZZ! │ ◄──────── │ │ │
+│ │ │ READY! └─────────────────────────────────┘ │
+│ │ Time to │ │
+│ │ eat! │ The Event Loop calls your callback │
+│ └──────────────┘ when the kitchen (Web API) is done │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+The 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.
+
+```javascript
+// You place your order (start async operation)
+setTimeout(function eatBurger() {
+ console.log('Eating my burger!') // This is the callback
+}, 5000)
+
+// You go sit down (your code continues)
+console.log('Sitting down, checking my phone...')
+console.log('Chatting with friends...')
+console.log('Reading the menu...')
+
+// Output:
+// Sitting down, checking my phone...
+// Chatting with friends...
+// Reading the menu...
+// Eating my burger! (5 seconds later)
+```
+
+---
+
+## Callbacks and Higher-Order Functions
+
+Callbacks and [higher-order functions](/concepts/higher-order-functions) go hand in hand:
+
+- A **higher-order function** is a function that accepts functions as arguments or returns them
+- A **callback** is the function being passed to a higher-order function
+
+```javascript
+// forEach is a HIGHER-ORDER FUNCTION (it accepts a function)
+// The arrow function is the CALLBACK (it's being passed in)
+
+const numbers = [1, 2, 3]
+
+numbers.forEach((num) => { // ← This is the callback
+ console.log(num * 2)
+})
+// 2, 4, 6
+```
+
+Every time you use `map`, `filter`, `forEach`, `reduce`, `sort`, or `find`, you're passing callbacks to higher-order functions:
+
+```javascript
+const users = [
+ { name: 'Alice', age: 25 },
+ { name: 'Bob', age: 17 },
+ { name: 'Charlie', age: 30 }
+]
+
+// filter accepts a callback that returns true/false
+const adults = users.filter(user => user.age >= 18)
+
+// map accepts a callback that transforms each element
+const names = users.map(user => user.name)
+
+// find accepts a callback that returns true when found
+const bob = users.find(user => user.name === 'Bob')
+
+// sort accepts a callback that compares two elements
+const byAge = users.sort((a, b) => a.age - b.age)
+```
+
+
+**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.
+
+
+---
+
+## Synchronous vs Asynchronous Callbacks
+
+Some callbacks run right away. Others run later. Getting this wrong will bite you.
+
+### Synchronous Callbacks
+
+**Synchronous callbacks** are executed immediately, during the function call. They block until complete.
+
+```javascript
+const numbers = [1, 2, 3, 4, 5]
+
+console.log('Before map')
+
+const doubled = numbers.map(num => {
+ console.log(`Doubling ${num}`)
+ return num * 2
+})
+
+console.log('After map')
+console.log(doubled)
+
+// Output (all synchronous, in order):
+// Before map
+// Doubling 1
+// Doubling 2
+// Doubling 3
+// Doubling 4
+// Doubling 5
+// After map
+// [2, 4, 6, 8, 10]
+```
+
+The callback runs for each element **before** `map` returns. Nothing else happens until it's done.
+
+**Common synchronous callbacks:**
+- Array methods: `map`, `filter`, `forEach`, `reduce`, `find`, `sort`, `every`, `some`
+- String methods: `replace` (with function)
+- Object methods: `Object.keys().forEach()`
+
+### Asynchronous Callbacks
+
+**Asynchronous callbacks** are executed later, after the current code finishes. They don't block.
+
+```javascript
+console.log('Before setTimeout')
+
+setTimeout(() => {
+ console.log('Inside setTimeout')
+}, 0) // Even with 0ms delay!
+
+console.log('After setTimeout')
+
+// Output:
+// Before setTimeout
+// After setTimeout
+// Inside setTimeout (runs AFTER all sync code)
+```
+
+Even with a 0ms delay, the callback runs **after** the synchronous code. This is because async callbacks go through the [event loop](/concepts/event-loop).
+
+**Common asynchronous callbacks:**
+- Timers: `setTimeout`, `setInterval`
+- Events: `addEventListener`, `onclick`
+- Network: `XMLHttpRequest.onload`, `fetch().then()`
+- Node.js I/O: `fs.readFile`, `http.get`
+
+### Comparison Table
+
+| Aspect | Synchronous Callbacks | Asynchronous Callbacks |
+|--------|----------------------|------------------------|
+| **When executed** | Immediately, during the function call | Later, via the event loop |
+| **Blocking** | Yes — code waits for completion | No — code continues immediately |
+| **Examples** | `map`, `filter`, `forEach`, `sort` | `setTimeout`, `addEventListener`, `fetch` |
+| **Use case** | Data transformation, iteration | I/O, user interaction, timers |
+| **Error handling** | Regular `try/catch` works | `try/catch` won't catch errors! |
+| **Return value** | Can return values | Return values usually ignored |
+
+### The Critical Difference: Error Handling
+
+This trips up almost everyone:
+
+```javascript
+// Synchronous callback - try/catch WORKS
+try {
+ [1, 2, 3].forEach(num => {
+ if (num === 2) throw new Error('Found 2!')
+ })
+} catch (error) {
+ console.log('Caught:', error.message) // "Caught: Found 2!"
+}
+
+// Asynchronous callback - try/catch DOES NOT WORK!
+try {
+ setTimeout(() => {
+ throw new Error('Async error!') // This error escapes!
+ }, 100)
+} catch (error) {
+ // This will NEVER run
+ console.log('Caught:', error.message)
+}
+// The error crashes your program!
+```
+
+Why? 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.
+
+---
+
+## How Callbacks Work with the Event Loop
+
+To understand async callbacks, you need to see how they work with the [event loop](/concepts/event-loop).
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ ASYNC CALLBACK LIFECYCLE │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ 1. YOUR CODE RUNS │
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ console.log('Start') │ │
+│ │ setTimeout(callback, 1000) // Register callback with Web API │ │
+│ │ console.log('End') │ │
+│ └─────────────────────────────────────────────────────────────────┘ │
+│ │ │
+│ ▼ │
+│ 2. WEB API HANDLES THE ASYNC OPERATION │
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ Timer starts counting... │ │
+│ │ (Your code continues running - it doesn't wait!) │ │
+│ └─────────────────────────────────────────────────────────────────┘ │
+│ │ │
+│ ▼ (after 1000ms) │
+│ 3. CALLBACK QUEUED │
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ Timer done! Callback added to Task Queue │ │
+│ │ [callback] ← waiting here │ │
+│ └─────────────────────────────────────────────────────────────────┘ │
+│ │ │
+│ ▼ (when call stack is empty) │
+│ 4. EVENT LOOP EXECUTES CALLBACK │
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ Event Loop: "Call stack empty? Let me grab that callback..." │ │
+│ │ callback() runs! │ │
+│ └─────────────────────────────────────────────────────────────────┘ │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+Let's trace through a real example:
+
+```javascript
+console.log('1: Script start')
+
+setTimeout(function first() {
+ console.log('2: First timeout')
+}, 0)
+
+setTimeout(function second() {
+ console.log('3: Second timeout')
+}, 0)
+
+console.log('4: Script end')
+```
+
+**Execution order:**
+
+1. `console.log('1: Script start')` — runs immediately → "1: Script start"
+2. `setTimeout(first, 0)` — registers `first` callback with Web APIs
+3. `setTimeout(second, 0)` — registers `second` callback with Web APIs
+4. `console.log('4: Script end')` — runs immediately → "4: Script end"
+5. Call stack is now empty
+6. Event Loop checks Task Queue — finds `first`
+7. `first()` runs → "2: First timeout"
+8. Event Loop checks Task Queue — finds `second`
+9. `second()` runs → "3: Second timeout"
+
+**Output:**
+```
+1: Script start
+4: Script end
+2: First timeout
+3: Second timeout
+```
+
+Even with a 0ms delay, the callbacks still run **after** all the synchronous code finishes.
+
+
+**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!
+
+
+---
+
+## Common Callback Patterns
+
+Here are the most common ways you'll see callbacks in the wild.
+
+### Pattern 1: Event Handlers
+
+The most common use of callbacks in browser JavaScript:
+
+```javascript
+// DOM events
+const button = document.getElementById('myButton')
+
+button.addEventListener('click', function handleClick(event) {
+ console.log('Button clicked!')
+ console.log('Event type:', event.type) // "click"
+ console.log('Target:', event.target) // the button element
+})
+
+// The callback receives an Event object with details about what happened
+```
+
+You can also use named functions for reusability:
+
+```javascript
+function handleClick(event) {
+ console.log('Clicked:', event.target.id)
+}
+
+function handleMouseOver(event) {
+ event.target.style.backgroundColor = 'yellow'
+}
+
+button.addEventListener('click', handleClick)
+button.addEventListener('mouseover', handleMouseOver)
+
+// Later, you can remove them:
+button.removeEventListener('click', handleClick)
+```
+
+### Pattern 2: Timers
+
+`setTimeout` and `setInterval` both accept callbacks:
+
+```javascript
+// setTimeout - runs once after delay
+const timeoutId = setTimeout(function() {
+ console.log('This runs once after 2 seconds')
+}, 2000)
+
+// Cancel it before it runs
+clearTimeout(timeoutId)
+
+// setInterval - runs repeatedly
+let count = 0
+const intervalId = setInterval(function() {
+ count++
+ console.log(`Count: ${count}`)
+
+ if (count >= 5) {
+ clearInterval(intervalId) // Stop after 5 times
+ console.log('Done!')
+ }
+}, 1000)
+```
+
+**Passing arguments to timer callbacks:**
+
+```javascript
+// Method 1: Closure (most common)
+const name = 'Alice'
+setTimeout(function() {
+ console.log(`Hello, ${name}!`)
+}, 1000)
+
+// Method 2: setTimeout's extra arguments
+setTimeout(function(greeting, name) {
+ console.log(`${greeting}, ${name}!`)
+}, 1000, 'Hello', 'Bob') // Extra args passed to callback
+
+// Method 3: Arrow function with closure
+const user = { name: 'Charlie' }
+setTimeout(() => console.log(`Hi, ${user.name}!`), 1000)
+```
+
+### Pattern 3: Array Iteration
+
+These are synchronous callbacks, but they're everywhere:
+
+```javascript
+const products = [
+ { name: 'Laptop', price: 999, inStock: true },
+ { name: 'Phone', price: 699, inStock: false },
+ { name: 'Tablet', price: 499, inStock: true }
+]
+
+// forEach - do something with each item
+products.forEach(product => {
+ console.log(`${product.name}: $${product.price}`)
+})
+
+// map - transform each item into something new
+const productNames = products.map(product => product.name)
+// ['Laptop', 'Phone', 'Tablet']
+
+// filter - keep only items that pass a test
+const available = products.filter(product => product.inStock)
+// [{ name: 'Laptop', ... }, { name: 'Tablet', ... }]
+
+// find - get the first item that passes a test
+const phone = products.find(product => product.name === 'Phone')
+// { name: 'Phone', price: 699, inStock: false }
+
+// reduce - combine all items into a single value
+const totalValue = products.reduce((sum, product) => sum + product.price, 0)
+// 2197
+```
+
+### Pattern 4: Custom Callbacks
+
+You can create your own functions that accept callbacks:
+
+```javascript
+// A function that does something and then calls you back
+function fetchUserData(userId, callback) {
+ // Simulate async operation
+ setTimeout(function() {
+ const user = { id: userId, name: 'Alice', email: 'alice@example.com' }
+ callback(user)
+ }, 1000)
+}
+
+// Using the function
+fetchUserData(123, function(user) {
+ console.log('Got user:', user.name)
+})
+console.log('Fetching user...')
+
+// Output:
+// Fetching user...
+// Got user: Alice (1 second later)
+```
+
+---
+
+## The Error-First Callback Pattern
+
+When 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").
+
+### The Convention
+
+```javascript
+// Error-first callback signature
+function callback(error, result) {
+ // error: null/undefined if success, Error object if failure
+ // result: the data if success, usually undefined if failure
+}
+```
+
+The 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.
+
+### Reading a File (Node.js Example)
+
+```javascript
+const fs = require('fs')
+
+fs.readFile('config.json', 'utf8', function(error, data) {
+ // ALWAYS check for error first!
+ if (error) {
+ console.error('Failed to read file:', error.message)
+ return // Important: stop execution!
+ }
+
+ // If we get here, error is null/undefined
+ console.log('File contents:', data)
+ const config = JSON.parse(data)
+ console.log('Config loaded:', config)
+})
+```
+
+### Why Put Error First?
+
+1. **Consistency** — Every callback has the same signature
+2. **Can't be ignored** — The error is the first thing you see
+3. **Early return** — Check for error, return early, then handle success
+4. **No exceptions** — Async errors can't be caught with try/catch
+
+### Creating Your Own Error-First Functions
+
+```javascript
+function divideAsync(a, b, callback) {
+ // Simulate async operation
+ setTimeout(function() {
+ // Check for errors
+ if (typeof a !== 'number' || typeof b !== 'number') {
+ callback(new Error('Both arguments must be numbers'))
+ return
+ }
+
+ if (b === 0) {
+ callback(new Error('Cannot divide by zero'))
+ return
+ }
+
+ // Success! Error is null, result is the value
+ const result = a / b
+ callback(null, result)
+ }, 100)
+}
+
+// Using it
+divideAsync(10, 2, function(error, result) {
+ if (error) {
+ console.error('Division failed:', error.message)
+ return
+ }
+ console.log('Result:', result) // Result: 5
+})
+
+divideAsync(10, 0, function(error, result) {
+ if (error) {
+ console.error('Division failed:', error.message) // "Cannot divide by zero"
+ return
+ }
+ console.log('Result:', result)
+})
+```
+
+### Common Mistake: Forgetting to Return
+
+```javascript
+// ❌ WRONG - code continues after error callback!
+function processData(data, callback) {
+ if (!data) {
+ callback(new Error('No data provided'))
+ // Oops! Execution continues...
+ }
+
+ // This runs even when there's an error!
+ const processed = transform(data) // Crash! data is undefined
+ callback(null, processed)
+}
+
+// ✓ CORRECT - return after error callback
+function processData(data, callback) {
+ if (!data) {
+ return callback(new Error('No data provided'))
+ // Or: callback(new Error(...)); return;
+ }
+
+ // This only runs if data exists
+ const processed = transform(data)
+ callback(null, processed)
+}
+```
+
+
+**Always return after calling an error callback!** Otherwise, your code continues executing with invalid data.
+
+
+---
+
+## Callback Hell: The Pyramid of Doom
+
+When you have multiple async operations that depend on each other, callbacks nest inside callbacks. This creates the infamous "callback hell" or "pyramid of doom."
+
+### The Problem
+
+Imagine a user authentication flow:
+
+1. Get user from database
+2. Verify password
+3. Get user's profile
+4. Get user's settings
+5. Render the dashboard
+
+With callbacks, this becomes:
+
+```javascript
+getUser(userId, function(error, user) {
+ if (error) {
+ handleError(error)
+ return
+ }
+
+ verifyPassword(user, password, function(error, isValid) {
+ if (error) {
+ handleError(error)
+ return
+ }
+
+ if (!isValid) {
+ handleError(new Error('Invalid password'))
+ return
+ }
+
+ getProfile(user.id, function(error, profile) {
+ if (error) {
+ handleError(error)
+ return
+ }
+
+ getSettings(user.id, function(error, settings) {
+ if (error) {
+ handleError(error)
+ return
+ }
+
+ renderDashboard(user, profile, settings, function(error) {
+ if (error) {
+ handleError(error)
+ return
+ }
+
+ console.log('Dashboard rendered!')
+ })
+ })
+ })
+ })
+})
+```
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ CALLBACK HELL │
+│ (The Pyramid of Doom) │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ getUser(id, function(err, user) { │
+│ verifyPassword(user, pw, function(err, valid) { │
+│ getProfile(user.id, function(err, profile) { │
+│ getSettings(user.id, function(err, settings) { │
+│ renderDashboard(user, profile, settings, function(err) { │
+│ // Finally! But look at this indentation... │
+│ }) │
+│ }) │
+│ }) │
+│ }) │
+│ }) │
+│ │
+│ Problems: │
+│ • Hard to read (horizontal scrolling) │
+│ • Hard to debug (which callback failed?) │
+│ • Hard to maintain (adding a step means more nesting) │
+│ • Error handling repeated at every level │
+│ • Variables from outer callbacks hard to track │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+### Why This Hurts
+
+1. **Readability** — Code flows right instead of down, requiring horizontal scrolling
+2. **Error handling** — Must be duplicated at every level
+3. **Debugging** — Stack traces become confusing
+4. **Maintenance** — Adding or removing steps is painful
+5. **Variable scope** — Variables from outer callbacks are hard to track
+6. **Testing** — Nearly impossible to unit test individual steps
+
+
+
+---
+
+## Escaping Callback Hell
+
+Here's how to escape the pyramid of doom.
+
+### Strategy 1: Named Functions
+
+Extract anonymous callbacks into named functions:
+
+```javascript
+// Before: Anonymous callback hell
+getData(function(err, data) {
+ processData(data, function(err, processed) {
+ saveData(processed, function(err) {
+ console.log('Done!')
+ })
+ })
+})
+
+// After: Named functions
+function handleData(err, data) {
+ if (err) return handleError(err)
+ processData(data, handleProcessed)
+}
+
+function handleProcessed(err, processed) {
+ if (err) return handleError(err)
+ saveData(processed, handleSaved)
+}
+
+function handleSaved(err) {
+ if (err) return handleError(err)
+ console.log('Done!')
+}
+
+function handleError(err) {
+ console.error('Error:', err.message)
+}
+
+// Start the chain
+getData(handleData)
+```
+
+**Benefits:**
+- Code flows vertically (easier to read)
+- Functions can be reused
+- Easier to debug (named functions in stack traces)
+- Easier to test individually
+
+### Strategy 2: Early Returns and Guard Clauses
+
+Keep the happy path at the lowest indentation level:
+
+```javascript
+// Instead of nested if/else
+function processUser(user, callback) {
+ validateUser(user, function(err, isValid) {
+ if (err) {
+ callback(err)
+ } else {
+ if (isValid) {
+ saveUser(user, function(err, savedUser) {
+ if (err) {
+ callback(err)
+ } else {
+ callback(null, savedUser)
+ }
+ })
+ } else {
+ callback(new Error('Invalid user'))
+ }
+ }
+ })
+}
+
+// Use early returns
+function processUser(user, callback) {
+ validateUser(user, function(err, isValid) {
+ if (err) return callback(err)
+ if (!isValid) return callback(new Error('Invalid user'))
+
+ saveUser(user, function(err, savedUser) {
+ if (err) return callback(err)
+ callback(null, savedUser)
+ })
+ })
+}
+```
+
+### Strategy 3: Modularization
+
+Split your code into smaller, focused modules:
+
+```javascript
+// auth.js
+function authenticateUser(credentials, callback) {
+ getUser(credentials.email, function(err, user) {
+ if (err) return callback(err)
+
+ verifyPassword(user, credentials.password, function(err, isValid) {
+ if (err) return callback(err)
+ if (!isValid) return callback(new Error('Invalid password'))
+ callback(null, user)
+ })
+ })
+}
+
+// profile.js
+function loadUserProfile(userId, callback) {
+ getProfile(userId, function(err, profile) {
+ if (err) return callback(err)
+
+ getSettings(userId, function(err, settings) {
+ if (err) return callback(err)
+ callback(null, { profile, settings })
+ })
+ })
+}
+
+// main.js
+authenticateUser(credentials, function(err, user) {
+ if (err) return handleError(err)
+
+ loadUserProfile(user.id, function(err, data) {
+ if (err) return handleError(err)
+ renderDashboard(user, data.profile, data.settings)
+ })
+})
+```
+
+### Strategy 4: Control Flow Libraries (Historical)
+
+Before Promises, libraries like [async.js](https://caolan.github.io/async/) helped manage callback flow:
+
+```javascript
+// Using async.js waterfall (each step passes result to next)
+async.waterfall([
+ function(callback) {
+ getUser(userId, callback)
+ },
+ function(user, callback) {
+ verifyPassword(user, password, function(err, isValid) {
+ callback(err, user, isValid)
+ })
+ },
+ function(user, isValid, callback) {
+ if (!isValid) return callback(new Error('Invalid password'))
+ getProfile(user.id, function(err, profile) {
+ callback(err, user, profile)
+ })
+ },
+ function(user, profile, callback) {
+ getSettings(user.id, function(err, settings) {
+ callback(err, user, profile, settings)
+ })
+ }
+], function(err, user, profile, settings) {
+ if (err) return handleError(err)
+ renderDashboard(user, profile, settings)
+})
+```
+
+### Strategy 5: Promises (The Modern Solution)
+
+[Promises](/concepts/promises) were invented specifically to solve callback hell:
+
+```javascript
+// The same flow with Promises
+getUser(userId)
+ .then(user => verifyPassword(user, password))
+ .then(({ user, isValid }) => {
+ if (!isValid) throw new Error('Invalid password')
+ return getProfile(user.id).then(profile => ({ user, profile }))
+ })
+ .then(({ user, profile }) => {
+ return getSettings(user.id).then(settings => ({ user, profile, settings }))
+ })
+ .then(({ user, profile, settings }) => {
+ renderDashboard(user, profile, settings)
+ })
+ .catch(handleError)
+```
+
+
+This 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).
+
+
+Or with [async/await](/concepts/async-await):
+
+```javascript
+// The same flow with async/await
+async function initDashboard(userId, password) {
+ try {
+ const user = await getUser(userId)
+ const isValid = await verifyPassword(user, password)
+
+ if (!isValid) throw new Error('Invalid password')
+
+ const profile = await getProfile(user.id)
+ const settings = await getSettings(user.id)
+
+ renderDashboard(user, profile, settings)
+ } catch (error) {
+ handleError(error)
+ }
+}
+```
+
+
+**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!
+
+
+---
+
+## Common Callback Mistakes
+
+### Mistake 1: Calling a Callback Multiple Times
+
+A callback should typically be called exactly once, either with an error or with a result:
+
+```javascript
+// ❌ WRONG - callback called multiple times!
+function fetchData(url, callback) {
+ fetch(url)
+ .then(response => {
+ callback(null, response) // Called on success
+ })
+ .catch(error => {
+ callback(error) // Called on error
+ })
+ .finally(() => {
+ callback(null, 'done') // Called ALWAYS, even after success or error!
+ })
+}
+
+// ✓ CORRECT - callback called exactly once
+function fetchData(url, callback) {
+ fetch(url)
+ .then(response => callback(null, response))
+ .catch(error => callback(error))
+}
+```
+
+### Mistake 2: Synchronous and Asynchronous Mixing (Zalgo)
+
+A 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:
+
+```javascript
+// ❌ WRONG - sometimes sync, sometimes async (Zalgo!)
+function getData(cache, callback) {
+ if (cache.has('data')) {
+ callback(null, cache.get('data')) // Sync!
+ return
+ }
+
+ fetchFromServer(function(err, data) {
+ callback(err, data) // Async!
+ })
+}
+
+// This causes unpredictable behavior:
+let value = 'initial'
+getData(cache, function(err, data) {
+ value = data
+})
+console.log(value) // "initial" or the data? Depends on cache!
+
+// ✓ CORRECT - always async
+function getData(cache, callback) {
+ if (cache.has('data')) {
+ // Use setTimeout to make it async (works in browsers and Node.js)
+ setTimeout(function() {
+ callback(null, cache.get('data'))
+ }, 0)
+ return
+ }
+
+ fetchFromServer(function(err, data) {
+ callback(err, data)
+ })
+}
+```
+
+### Mistake 3: Losing `this` Context
+
+Regular functions lose their `this` binding when used as callbacks:
+
+```javascript
+// ❌ WRONG - this is undefined/global
+const user = {
+ name: 'Alice',
+ greetLater: function() {
+ setTimeout(function() {
+ console.log(`Hello, ${this.name}!`) // this.name is undefined!
+ }, 1000)
+ }
+}
+user.greetLater() // "Hello, undefined!"
+
+// ✓ CORRECT - Use arrow function (inherits this)
+const user = {
+ name: 'Alice',
+ greetLater: function() {
+ setTimeout(() => {
+ console.log(`Hello, ${this.name}!`) // Arrow function keeps this
+ }, 1000)
+ }
+}
+user.greetLater() // "Hello, Alice!"
+
+// ✓ CORRECT - Use bind
+const user = {
+ name: 'Alice',
+ greetLater: function() {
+ setTimeout(function() {
+ console.log(`Hello, ${this.name}!`)
+ }.bind(this), 1000) // Explicitly bind this
+ }
+}
+user.greetLater() // "Hello, Alice!"
+
+// ✓ CORRECT - Save reference to this
+const user = {
+ name: 'Alice',
+ greetLater: function() {
+ const self = this // Save reference
+ setTimeout(function() {
+ console.log(`Hello, ${self.name}!`)
+ }, 1000)
+ }
+}
+user.greetLater() // "Hello, Alice!"
+```
+
+### Mistake 4: Not Handling Errors
+
+Always handle errors in async callbacks. Unhandled errors can crash your application:
+
+```javascript
+// ❌ WRONG - error ignored
+fs.readFile('config.json', function(err, data) {
+ const config = JSON.parse(data) // Crashes if err exists!
+ startApp(config)
+})
+
+// ✓ CORRECT - error handled
+fs.readFile('config.json', function(err, data) {
+ if (err) {
+ console.error('Could not read config:', err.message)
+ process.exit(1)
+ return
+ }
+
+ try {
+ const config = JSON.parse(data)
+ startApp(config)
+ } catch (parseError) {
+ console.error('Invalid JSON in config:', parseError.message)
+ process.exit(1)
+ }
+})
+```
+
+---
+
+## Historical Context: Why JavaScript Uses Callbacks
+
+Understanding *why* JavaScript uses callbacks helps everything click into place.
+
+### The Birth of JavaScript (1995)
+
+JavaScript 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.
+
+### The Single-Threaded Design
+
+JavaScript was designed to be **single-threaded**: one thing at a time. Why?
+
+1. **Simplicity** — No race conditions, deadlocks, or complex synchronization
+2. **DOM Safety** — Multiple threads modifying the DOM would cause chaos
+3. **Browser Reality** — Early browsers couldn't handle multi-threaded scripts
+
+But single-threaded means a problem: **you can't block waiting for things.**
+
+If 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.
+
+### The Callback Solution
+
+Callbacks solved this problem neatly:
+
+1. **Register interest** — "When this happens, call this function"
+2. **Continue immediately** — Don't block, keep the UI responsive
+3. **React later** — When the event occurs, the callback runs
+
+```javascript
+// This pattern was there from day one
+element.onclick = function() {
+ alert('Clicked!')
+}
+
+// The page doesn't freeze waiting for a click
+// JavaScript registers the callback and moves on
+// When clicked, the callback runs
+```
+
+### The Evolution
+
+| Year | Development |
+|------|-------------|
+| 1995 | JavaScript created with event callbacks |
+| 1999 | XMLHttpRequest (AJAX) — async HTTP with callbacks |
+| 2009 | Node.js — callbacks for server-side I/O |
+| 2012 | Callback hell becomes a recognized problem |
+| 2015 | ES6 Promises — official solution to callback hell |
+| 2017 | ES8 async/await — syntactic sugar for Promises |
+
+### Callbacks Are Still The Foundation
+
+Even with Promises and async/await, callbacks are everywhere:
+
+- **Event handlers** still use callbacks
+- **Array methods** still use callbacks
+- **Promises** use callbacks internally (`.then(callback)`)
+- **async/await** is syntactic sugar over Promise callbacks
+
+Callbacks aren't obsolete. They're the foundation that everything else builds upon.
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **A callback is a function passed to another function** to be executed later — nothing magical
+
+2. **Callbacks can be synchronous or asynchronous** — array methods are sync, timers and events are async
+
+3. **Higher-order functions and callbacks are two sides of the same coin** — one accepts, one is passed
+
+4. **Async callbacks go through the event loop** — they never run until all sync code finishes
+
+5. **Error-first callbacks: `callback(error, result)`** — always check error first, return after handling
+
+6. **You can't use try/catch for async callbacks** — the catch is gone by the time the callback runs
+
+7. **Callback hell is real** — deeply nested callbacks become unreadable and unmaintainable
+
+8. **Escape callback hell with:** named functions, modularization, early returns, or Promises
+
+9. **Promises were invented to solve callback problems** — but they still use callbacks under the hood
+
+10. **Callbacks are the foundation** — events, Promises, async/await all build on callbacks
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ **Synchronous callbacks** execute immediately, during the function call. They block until complete. Examples: `map`, `filter`, `forEach`.
+
+ ```javascript
+ [1, 2, 3].forEach(n => console.log(n)) // Runs immediately, blocks
+ console.log('Done') // Runs after forEach completes
+ ```
+
+ **Asynchronous callbacks** execute later, via the event loop. They don't block. Examples: `setTimeout`, `addEventListener`, `fs.readFile`.
+
+ ```javascript
+ setTimeout(() => console.log('Timer'), 0) // Registers, doesn't block
+ console.log('Done') // Runs BEFORE the timer callback
+ ```
+
+
+
+ **Answer:**
+
+ The error-first convention exists because:
+
+ 1. **Consistency** — Every async callback has the same signature: `(error, result)`
+ 2. **Can't be ignored** — The error is the first thing you must deal with
+ 3. **Forces handling** — You naturally check for errors before using results
+ 4. **No exceptions** — Async errors can't be caught with try/catch, so they must be passed
+
+ ```javascript
+ fs.readFile('file.txt', (error, data) => {
+ if (error) {
+ // Handle error FIRST
+ console.error(error)
+ return
+ }
+ // Safe to use data
+ console.log(data)
+ })
+ ```
+
+
+
+ ```javascript
+ console.log('A')
+
+ setTimeout(() => console.log('B'), 0)
+
+ console.log('C')
+
+ setTimeout(() => console.log('D'), 0)
+
+ console.log('E')
+ ```
+
+ **Answer:** `A`, `C`, `E`, `B`, `D`
+
+ **Explanation:**
+ 1. `console.log('A')` — sync, runs immediately → "A"
+ 2. `setTimeout(..., 0)` — registers callback B, continues
+ 3. `console.log('C')` — sync, runs immediately → "C"
+ 4. `setTimeout(..., 0)` — registers callback D, continues
+ 5. `console.log('E')` — sync, runs immediately → "E"
+ 6. Call stack empty → event loop runs callback B → "B"
+ 7. Event loop runs callback D → "D"
+
+ Even with 0ms delay, setTimeout callbacks run after all sync code.
+
+
+
+ **Answer:** Three common approaches:
+
+ **1. Arrow functions** (recommended — they inherit `this` from enclosing scope):
+ ```javascript
+ const obj = {
+ name: 'Alice',
+ greet() {
+ setTimeout(() => {
+ console.log(this.name) // "Alice"
+ }, 100)
+ }
+ }
+ ```
+
+ **2. Using `bind()`**:
+ ```javascript
+ setTimeout(function() {
+ console.log(this.name)
+ }.bind(this), 100)
+ ```
+
+ **3. Saving a reference**:
+ ```javascript
+ const self = this
+ setTimeout(function() {
+ console.log(self.name)
+ }, 100)
+ ```
+
+
+
+ **Answer:**
+
+ 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.
+
+ ```javascript
+ try {
+ setTimeout(() => {
+ throw new Error('Async error!') // This escapes!
+ }, 100)
+ } catch (e) {
+ // This NEVER catches the error
+ console.log('Caught:', e)
+ }
+
+ // The error crashes the program because:
+ // 1. try/catch runs immediately
+ // 2. setTimeout registers callback and returns
+ // 3. try/catch completes (nothing thrown yet!)
+ // 4. 100ms later, callback runs and throws
+ // 5. No try/catch exists at that point
+ ```
+
+ This is why we use error-first callbacks or Promise `.catch()` for async error handling.
+
+
+
+ **Answer:**
+
+ **1. Named functions** — Extract callbacks into named functions:
+ ```javascript
+ function handleUser(err, user) {
+ if (err) return handleError(err)
+ getProfile(user.id, handleProfile)
+ }
+ getUser(userId, handleUser)
+ ```
+
+ **2. Modularization** — Split into separate modules/functions:
+ ```javascript
+ // auth.js exports authenticateUser()
+ // profile.js exports loadProfile()
+ // main.js composes them
+ ```
+
+ **3. Promises/async-await** — Use modern async patterns:
+ ```javascript
+ const user = await getUser(userId)
+ const profile = await getProfile(user.id)
+ ```
+
+ Other approaches: control flow libraries (async.js), early returns, keeping nesting shallow.
+
+
+
+---
+
+## Related Concepts
+
+
+
+ How JavaScript schedules and executes async callbacks
+
+
+ Modern solution to callback hell
+
+
+ Cleaner syntax for Promise-based async code
+
+
+ Functions that accept or return other functions
+
+
+
+---
+
+## Reference
+
+
+
+ Official MDN glossary definition of callback functions
+
+
+ Documentation for the setTimeout timer function
+
+
+ How to register event callbacks on DOM elements
+
+
+ Synchronous callback pattern with array iteration
+
+
+
+## Articles
+
+
+
+ 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.
+
+
+ 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.
+
+
+
+
+## Videos
+
+
+
+ Mosh uses a movie database example that shows callbacks in a realistic context. Great production quality with on-screen code highlighting.
+
+
+ Kyle explains callbacks in under 8 minutes with zero fluff. Perfect if you want a quick refresher without sitting through a long tutorial.
+
+
+ MPJ's signature style makes this feel like a conversation, not a lecture. Explains the "why" behind callbacks, not just the "how."
+
+
+ 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.
+
+
+ Walks through callbacks with a setTimeout example, then shows how to create your own callback-accepting functions. Good for hands-on learners.
+
+
diff --git a/docs/concepts/clean-code.mdx b/docs/concepts/clean-code.mdx
new file mode 100644
index 00000000..45f5d336
--- /dev/null
+++ b/docs/concepts/clean-code.mdx
@@ -0,0 +1,900 @@
+---
+title: "Clean Code: Writing Readable JavaScript"
+sidebarTitle: "Clean Code: Writing Readable JavaScript"
+description: "Learn clean code principles for JavaScript. Covers meaningful naming, small functions, DRY, avoiding side effects, and best practices to write maintainable code."
+---
+
+Why 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?
+
+```javascript
+// Which would you rather debug at 2am?
+
+// Version A
+function p(a, b) {
+ let x = 0
+ for (let i = 0; i < a.length; i++) {
+ if (a[i].s === 1) x += a[i].p * b
+ }
+ return x
+}
+
+// Version B
+function calculateActiveProductsTotal(products, taxRate) {
+ let total = 0
+ for (const product of products) {
+ if (product.status === PRODUCT_STATUS.ACTIVE) {
+ total += product.price * taxRate
+ }
+ }
+ return total
+}
+```
+
+**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.
+
+
+**What you'll learn in this guide:**
+- What makes code "clean" and why it matters
+- Naming conventions that make code self-documenting
+- How to write small, focused functions that do one thing
+- The DRY principle and when to apply it
+- How to avoid side effects and write predictable code
+- Using early returns to reduce nesting
+- When to write comments (and when not to)
+- SOLID principles applied to JavaScript
+
+
+---
+
+## The Newspaper Analogy
+
+Think 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.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ CODE LIKE A NEWSPAPER │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ // HEADLINE: What does this module do? │
+│ export function processUserOrder(userId, orderId) { │
+│ const user = getUser(userId) │
+│ const order = getOrder(orderId) │
+│ validateOrder(user, order) │
+│ return chargeAndShip(user, order) │
+│ } │
+│ │
+│ // DETAILS: How does it do it? │
+│ function getUser(userId) { ... } │
+│ function getOrder(orderId) { ... } │
+│ function validateOrder(user, order) { ... } │
+│ function chargeAndShip(user, order) { ... } │
+│ │
+│ Read top-to-bottom. The "what" comes before the "how". │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+---
+
+## Meaningful Naming
+
+Names are everywhere in code: variables, functions, classes, files. Good names make comments unnecessary. Bad names make simple code confusing.
+
+### Use Pronounceable, Searchable Names
+
+```javascript
+// ❌ What does this even mean?
+const yyyymmdstr = moment().format('YYYY/MM/DD')
+const d = new Date()
+const t = d.getTime()
+
+// ✓ Crystal clear
+const currentDate = moment().format('YYYY/MM/DD')
+const now = new Date()
+const timestamp = now.getTime()
+```
+
+### Use the Same Word for the Same Concept
+
+Pick one word per concept and stick with it. If you fetch users with `getUser()`, don't also have `fetchClient()` and `retrieveCustomer()`.
+
+```javascript
+// ❌ Inconsistent - which one do I use?
+getUserInfo()
+fetchClientData()
+retrieveCustomerRecord()
+
+// ✓ Consistent vocabulary
+getUser()
+getClient()
+getCustomer()
+```
+
+### Avoid Mental Mapping
+
+Single-letter variables force readers to remember what `a`, `x`, or `l` mean. Be explicit.
+
+```javascript
+// ❌ What is 'l'? A number? A location? A letter?
+locations.forEach(l => {
+ doStuff()
+ // ... 50 lines later
+ dispatch(l) // Wait, what was 'l' again?
+})
+
+// ✓ No guessing required
+locations.forEach(location => {
+ doStuff()
+ dispatch(location)
+})
+```
+
+### Don't Add Unnecessary Context
+
+If your class is called `Car`, you don't need `carMake`, `carModel`, `carColor`. The context is already there.
+
+```javascript
+// ❌ Redundant prefixes
+const Car = {
+ carMake: 'Honda',
+ carModel: 'Accord',
+ carColor: 'Blue'
+}
+
+// ✓ Context is already clear
+const Car = {
+ make: 'Honda',
+ model: 'Accord',
+ color: 'Blue'
+}
+```
+
+---
+
+## Functions Should Do One Thing
+
+This is the single most important rule in clean code. When functions do one thing, they're easier to name, easier to test, and easier to reuse.
+
+### Keep Functions Small and Focused
+
+```javascript
+// ❌ This function does too many things
+function emailClients(clients) {
+ clients.forEach(client => {
+ const clientRecord = database.lookup(client)
+ if (clientRecord.isActive()) {
+ email(client)
+ }
+ })
+}
+
+// ✓ Each function has one job
+function emailActiveClients(clients) {
+ clients
+ .filter(isActiveClient)
+ .forEach(email)
+}
+
+function isActiveClient(client) {
+ const clientRecord = database.lookup(client)
+ return clientRecord.isActive()
+}
+```
+
+### Limit Function Parameters
+
+Two or fewer parameters is ideal. If you need more, use an object with destructuring. This also makes the call site self-documenting.
+
+```javascript
+// ❌ What do these arguments mean?
+createMenu('Settings', 'User preferences', 'Save', true)
+
+// ✓ Self-documenting with destructuring
+createMenu({
+ title: 'Settings',
+ body: 'User preferences',
+ buttonText: 'Save',
+ cancellable: true
+})
+
+function createMenu({ title, body, buttonText, cancellable = false }) {
+ // ...
+}
+```
+
+### Don't Use Boolean Flags
+
+A boolean parameter is a sign that the function does more than one thing. Split it into two functions instead.
+
+```javascript
+// ❌ Boolean flag = function does two things
+function createFile(name, isTemp) {
+ if (isTemp) {
+ fs.create(`./temp/${name}`)
+ } else {
+ fs.create(name)
+ }
+}
+
+// ✓ Two focused functions
+function createFile(name) {
+ fs.create(name)
+}
+
+function createTempFile(name) {
+ createFile(`./temp/${name}`)
+}
+```
+
+---
+
+## Avoid Magic Numbers and Strings
+
+Magic values are unexplained numbers or strings scattered through your code. They make code hard to understand and hard to change.
+
+```javascript
+// ❌ What is 86400000? Why 18?
+setTimeout(blastOff, 86400000)
+
+if (user.age > 18) {
+ allowAccess()
+}
+
+if (status === 1) {
+ // ...
+}
+
+// ✓ Named constants are searchable and self-documenting
+const MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000
+const MINIMUM_LEGAL_AGE = 18
+const STATUS = {
+ ACTIVE: 1,
+ INACTIVE: 0
+}
+
+setTimeout(blastOff, MILLISECONDS_PER_DAY)
+
+if (user.age > MINIMUM_LEGAL_AGE) {
+ allowAccess()
+}
+
+if (status === STATUS.ACTIVE) {
+ // ...
+}
+```
+
+
+**Pro tip:** ESLint's `no-magic-numbers` rule can automatically flag magic numbers in your code.
+
+
+---
+
+## DRY: Don't Repeat Yourself
+
+Duplicate code means multiple places to update when logic changes. But be careful: a bad abstraction is worse than duplication. Only abstract when you see a clear pattern.
+
+```javascript
+// ❌ Duplicate logic
+function showDeveloperList(developers) {
+ developers.forEach(dev => {
+ const salary = dev.calculateSalary()
+ const experience = dev.getExperience()
+ const githubLink = dev.getGithubLink()
+ render({ salary, experience, githubLink })
+ })
+}
+
+function showManagerList(managers) {
+ managers.forEach(mgr => {
+ const salary = mgr.calculateSalary()
+ const experience = mgr.getExperience()
+ const portfolio = mgr.getPortfolio()
+ render({ salary, experience, portfolio })
+ })
+}
+
+// ✓ Unified with type-specific handling
+function showEmployeeList(employees) {
+ employees.forEach(employee => {
+ const baseData = {
+ salary: employee.calculateSalary(),
+ experience: employee.getExperience()
+ }
+
+ const extraData = employee.type === 'developer'
+ ? { githubLink: employee.getGithubLink() }
+ : { portfolio: employee.getPortfolio() }
+
+ render({ ...baseData, ...extraData })
+ })
+}
+```
+
+---
+
+## Avoid Side Effects
+
+A 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.
+
+```javascript
+// ❌ Mutates the original array - side effect!
+function addItemToCart(cart, item) {
+ cart.push({ item, date: Date.now() })
+}
+
+// ✓ Returns a new array - no side effects
+function addItemToCart(cart, item) {
+ return [...cart, { item, date: Date.now() }]
+}
+```
+
+```javascript
+// ❌ Modifies global state
+let name = 'Ryan McDermott'
+
+function splitName() {
+ name = name.split(' ') // Mutates global!
+}
+
+// ✓ Pure function - no globals modified
+function splitName(name) {
+ return name.split(' ')
+}
+
+const fullName = 'Ryan McDermott'
+const nameParts = splitName(fullName)
+```
+
+---
+
+## Early Returns and Guard Clauses
+
+Deeply nested code is hard to follow. Use early returns to handle edge cases first, then write the main logic without extra indentation.
+
+```javascript
+// ❌ Deeply nested - hard to follow
+function getPayAmount(employee) {
+ let result
+ if (employee.isSeparated) {
+ result = { amount: 0, reason: 'separated' }
+ } else {
+ if (employee.isRetired) {
+ result = { amount: 0, reason: 'retired' }
+ } else {
+ // ... complex salary calculation
+ result = { amount: salary, reason: 'employed' }
+ }
+ }
+ return result
+}
+
+// ✓ Guard clauses - flat and readable
+function getPayAmount(employee) {
+ if (employee.isSeparated) {
+ return { amount: 0, reason: 'separated' }
+ }
+
+ if (employee.isRetired) {
+ return { amount: 0, reason: 'retired' }
+ }
+
+ // Main logic at the top level
+ const salary = calculateSalary(employee)
+ return { amount: salary, reason: 'employed' }
+}
+```
+
+The same applies to loops. Use `continue` to skip iterations instead of nesting:
+
+```javascript
+// ❌ Unnecessary nesting
+for (const user of users) {
+ if (user.isActive) {
+ if (user.hasPermission) {
+ processUser(user)
+ }
+ }
+}
+
+// ✓ Flat and scannable
+for (const user of users) {
+ if (!user.isActive) continue
+ if (!user.hasPermission) continue
+
+ processUser(user)
+}
+```
+
+---
+
+## Comments: Less is More
+
+Good code mostly documents itself. Comments should explain *why*, not *what*. If you need a comment to explain what code does, consider rewriting the code to be clearer.
+
+### Don't State the Obvious
+
+```javascript
+// ❌ These comments add nothing
+function hashIt(data) {
+ // The hash
+ let hash = 0
+
+ // Length of string
+ const length = data.length
+
+ // Loop through every character
+ for (let i = 0; i < length; i++) {
+ // Get character code
+ const char = data.charCodeAt(i)
+ // Make the hash
+ hash = (hash << 5) - hash + char
+ // Convert to 32-bit integer
+ hash &= hash
+ }
+ return hash
+}
+
+// ✓ Only comment what's not obvious
+function hashIt(data) {
+ let hash = 0
+ const length = data.length
+
+ for (let i = 0; i < length; i++) {
+ const char = data.charCodeAt(i)
+ hash = (hash << 5) - hash + char
+ hash &= hash // Convert to 32-bit integer
+ }
+ return hash
+}
+```
+
+### Don't Leave Commented-Out Code
+
+That's what version control is for. Delete it. If you need it later, check the git history.
+
+```javascript
+// ❌ Dead code cluttering the file
+doStuff()
+// doOtherStuff()
+// doSomeMoreStuff()
+// doSoMuchStuff()
+
+// ✓ Clean
+doStuff()
+```
+
+### Don't Write Journal Comments
+
+Git log exists for a reason.
+
+```javascript
+// ❌ This is what git history is for
+/**
+ * 2016-12-20: Removed monads (RM)
+ * 2016-10-01: Added special monads (JP)
+ * 2016-02-03: Removed type-checking (LI)
+ */
+function combine(a, b) {
+ return a + b
+}
+
+// ✓ Just the code
+function combine(a, b) {
+ return a + b
+}
+```
+
+---
+
+## SOLID Principles in JavaScript
+
+SOLID is a set of five principles that help you write maintainable, flexible code. Here's how they apply to JavaScript:
+
+
+
+ A class or module should have only one reason to change.
+
+ ```javascript
+ // ❌ UserSettings handles both settings AND authentication
+ class UserSettings {
+ constructor(user) {
+ this.user = user
+ }
+
+ changeSettings(settings) {
+ if (this.verifyCredentials()) {
+ // update settings
+ }
+ }
+
+ verifyCredentials() {
+ // authentication logic
+ }
+ }
+
+ // ✓ Separate responsibilities
+ class UserAuth {
+ constructor(user) {
+ this.user = user
+ }
+
+ verifyCredentials() {
+ // authentication logic
+ }
+ }
+
+ class UserSettings {
+ constructor(user, auth) {
+ this.user = user
+ this.auth = auth
+ }
+
+ changeSettings(settings) {
+ if (this.auth.verifyCredentials()) {
+ // update settings
+ }
+ }
+ }
+ ```
+
+
+
+ Code should be open for extension but closed for modification. Add new features by adding new code, not changing existing code.
+
+ ```javascript
+ // ❌ Must modify this function for every new shape
+ function getArea(shape) {
+ if (shape.type === 'circle') {
+ return Math.PI * shape.radius ** 2
+ } else if (shape.type === 'rectangle') {
+ return shape.width * shape.height
+ }
+ // Add another if for every new shape...
+ }
+
+ // ✓ Extend by adding new classes
+ class Shape {
+ getArea() {
+ throw new Error('getArea must be implemented')
+ }
+ }
+
+ class Circle extends Shape {
+ constructor(radius) {
+ super()
+ this.radius = radius
+ }
+
+ getArea() {
+ return Math.PI * this.radius ** 2
+ }
+ }
+
+ class Rectangle extends Shape {
+ constructor(width, height) {
+ super()
+ this.width = width
+ this.height = height
+ }
+
+ getArea() {
+ return this.width * this.height
+ }
+ }
+ ```
+
+
+
+ Child classes should be usable wherever parent classes are expected without breaking the code.
+
+ ```javascript
+ // ❌ Square breaks when used where Rectangle is expected
+ class Rectangle {
+ constructor() {
+ this.width = 0
+ this.height = 0
+ }
+
+ setWidth(width) {
+ this.width = width
+ }
+
+ setHeight(height) {
+ this.height = height
+ }
+
+ getArea() {
+ return this.width * this.height
+ }
+ }
+
+ class Square extends Rectangle {
+ setWidth(width) {
+ this.width = width
+ this.height = width // Breaks LSP!
+ }
+
+ setHeight(height) {
+ this.width = height
+ this.height = height
+ }
+ }
+
+ // This fails for Square - expects 20, gets 25
+ function calculateAreas(rectangles) {
+ rectangles.forEach(rect => {
+ rect.setWidth(4)
+ rect.setHeight(5)
+ console.log(rect.getArea()) // Square returns 25, not 20!
+ })
+ }
+
+ // ✓ Better: separate classes, no inheritance relationship
+ class Rectangle {
+ constructor(width, height) {
+ this.width = width
+ this.height = height
+ }
+
+ getArea() {
+ return this.width * this.height
+ }
+ }
+
+ class Square {
+ constructor(side) {
+ this.side = side
+ }
+
+ getArea() {
+ return this.side * this.side
+ }
+ }
+ ```
+
+
+
+ Don't force clients to depend on methods they don't use. In JavaScript, use optional configuration objects instead of requiring many parameters.
+
+ ```javascript
+ // ❌ Forcing clients to provide options they don't need
+ class DOMTraverser {
+ constructor(settings) {
+ this.settings = settings
+ this.rootNode = settings.rootNode
+ this.settings.animationModule.setup() // Required even if not needed!
+ }
+ }
+
+ const traverser = new DOMTraverser({
+ rootNode: document.body,
+ animationModule: { setup() {} } // Must provide even if not animating
+ })
+
+ // ✓ Make features optional
+ class DOMTraverser {
+ constructor(settings) {
+ this.settings = settings
+ this.rootNode = settings.rootNode
+
+ if (settings.animationModule) {
+ settings.animationModule.setup()
+ }
+ }
+ }
+
+ const traverser = new DOMTraverser({
+ rootNode: document.body
+ // animationModule is optional now
+ })
+ ```
+
+
+
+ Depend on abstractions, not concrete implementations. Inject dependencies rather than instantiating them inside your classes.
+
+ ```javascript
+ // ❌ Tightly coupled to InventoryRequester
+ class InventoryTracker {
+ constructor(items) {
+ this.items = items
+ this.requester = new InventoryRequester() // Hard dependency
+ }
+ }
+
+ // ✓ Dependency injection
+ class InventoryTracker {
+ constructor(items, requester) {
+ this.items = items
+ this.requester = requester // Injected - can be any requester
+ }
+ }
+ ```
+
+
+
+---
+
+## Write Testable Code
+
+Functions 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.
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **Names matter** — Use meaningful, pronounceable, searchable names. Good names eliminate the need for comments.
+
+2. **Functions should do one thing** — This is the most important rule. Small, focused functions are easier to name, test, and reuse.
+
+3. **Limit function parameters** — Two or fewer is ideal. Use object destructuring for more.
+
+4. **Eliminate magic numbers** — Use named constants that explain what values mean.
+
+5. **DRY, but don't over-abstract** — Remove duplication, but a bad abstraction is worse than duplication.
+
+6. **Avoid side effects** — Prefer pure functions that don't mutate inputs or global state.
+
+7. **Use early returns** — Guard clauses reduce nesting and make code easier to follow.
+
+8. **Comments explain why, not what** — If you need to explain what code does, rewrite the code.
+
+9. **Delete dead code** — Commented-out code and unused functions clutter your codebase. Git remembers.
+
+10. **Use tools** — ESLint catches issues, Prettier handles formatting. Don't argue about style.
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ ```javascript
+ function process(data) {
+ // ...
+ }
+ ```
+
+ **Answer:**
+
+ 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.
+
+
+
+ ```javascript
+ function createUser(name, email, age, isAdmin, sendWelcomeEmail) {
+ // ...
+ }
+ ```
+
+ **Answer:**
+
+ 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:
+
+ ```javascript
+ function createUser({ name, email, age, isAdmin = false }) {
+ // ...
+ }
+
+ function sendWelcomeEmail(user) {
+ // Separate function for separate concern
+ }
+ ```
+
+
+
+ **Answer:**
+
+ Write comments when you need to explain *why* something is done a certain way, especially for:
+ - Business logic that isn't obvious from the code
+ - Workarounds for bugs or edge cases
+ - Legal or licensing requirements
+ - Complex algorithms where the approach isn't self-evident
+
+ Don't write comments that explain *what* the code does. If the code needs explanation, rewrite it to be clearer.
+
+
+
+ **Answer:**
+
+ A magic number is an unexplained numeric literal in code, like `86400000` or `18`. They're bad because:
+ - You can't search for what they mean
+ - They don't explain their purpose
+ - If the value needs to change, you have to find every occurrence
+
+ Replace with named constants: `MILLISECONDS_PER_DAY` or `MINIMUM_LEGAL_AGE`.
+
+
+
+ ```javascript
+ function processUser(user) {
+ if (user) {
+ if (user.isActive) {
+ if (user.hasPermission) {
+ return doSomething(user)
+ }
+ }
+ }
+ return null
+ }
+ ```
+
+ **Answer:**
+
+ Use guard clauses (early returns) to flatten the nesting:
+
+ ```javascript
+ function processUser(user) {
+ if (!user) return null
+ if (!user.isActive) return null
+ if (!user.hasPermission) return null
+
+ return doSomething(user)
+ }
+ ```
+
+ Each guard clause handles one edge case, and the main logic sits at the top level without indentation.
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Deep dive into functions without side effects and why they make code predictable
+
+
+ ES6+ features like destructuring and arrow functions that enable cleaner code
+
+
+ How to handle errors cleanly without swallowing exceptions or cluttering code
+
+
+ Reusable solutions that embody clean code principles at a higher level
+
+
+
+---
+
+## Books
+
+
+ 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.
+
+
+## Articles
+
+
+
+ The definitive JavaScript adaptation of Clean Code principles with 94k+ GitHub stars. Every example is practical and immediately applicable to your code.
+
+
+ freeCodeCamp's beginner-friendly introduction covering the "why" behind each clean code principle. Great starting point if you're new to these concepts.
+
+
+ javascript.info's practical guide to syntax, formatting, and style. Includes a visual cheat sheet you can reference while coding.
+
+
+ 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.
+
+
+
+## Videos
+
+
+
+ Fireship's fast-paced video showing modern patterns that replace outdated approaches. Great examples of before/after refactoring.
+
+
+ freeCodeCamp's multi-part series covering each clean code principle in depth with live coding. Perfect for visual learners.
+
+
+ Robert C. Martin himself explaining clean code fundamentals. Hearing it from the source gives you the philosophy behind the principles.
+
+
diff --git a/docs/concepts/currying-composition.mdx b/docs/concepts/currying-composition.mdx
new file mode 100644
index 00000000..a226f1d6
--- /dev/null
+++ b/docs/concepts/currying-composition.mdx
@@ -0,0 +1,1351 @@
+---
+title: "Currying & Composition: Functional Patterns in JavaScript"
+sidebarTitle: "Currying & Composition: Functional Patterns"
+description: "Learn currying and function composition in JavaScript. Build reusable functions from simple pieces using curry, compose, and pipe for cleaner, modular code."
+---
+
+How 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?
+
+```javascript
+// Currying: one argument at a time
+const add = a => b => c => a + b + c
+add(1)(2)(3) // 6
+
+// Composition: chain functions together
+const process = pipe(
+ getName,
+ trim,
+ capitalize
+)
+process({ name: " alice " }) // "Alice"
+```
+
+These 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.
+
+
+**What you'll learn in this guide:**
+- What currying is and how `add(1)(2)(3)` actually works
+- The difference between currying and partial application (they're not the same!)
+- How to implement your own `curry()` helper function
+- What function composition is and why it matters
+- How to build `compose()` and `pipe()` from scratch
+- Why currying and composition work so well together
+- When to use libraries like Lodash vs vanilla JavaScript
+- Real-world patterns used in production codebases
+
+
+
+**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.
+
+
+---
+
+## What is Currying?
+
+**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.
+
+Instead 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.
+
+```javascript
+// Regular function: takes all arguments at once
+function add(a, b, c) {
+ return a + b + c
+}
+add(1, 2, 3) // 6
+
+// Curried function: takes one argument at a time
+function curriedAdd(a) {
+ return function(b) {
+ return function(c) {
+ return a + b + c
+ }
+ }
+}
+curriedAdd(1)(2)(3) // 6
+```
+
+With arrow functions, curried functions become beautifully concise:
+
+```javascript
+const add = a => b => c => a + b + c
+add(1)(2)(3) // 6
+```
+
+
+**Key insight:** Currying doesn't call the function. It transforms it. The original logic only runs when ALL arguments have been provided.
+
+
+---
+
+## The Pizza Restaurant Analogy
+
+Imagine 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:
+
+1. **Size station:** "What size?" → "Large" → You get a ticket for a large pizza
+2. **Crust station:** "What crust?" → "Thin" → Your ticket now says large thin-crust
+3. **Toppings station:** "What toppings?" → "Pepperoni" → Your pizza is made!
+
+Each station remembers your previous choices and waits for just one more piece of information.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ THE PIZZA RESTAURANT ANALOGY │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ orderPizza(size)(crust)(toppings) │
+│ │
+│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
+│ │ SIZE STATION │ │ CRUST STATION │ │TOPPING STATION│ │
+│ │ │ │ │ │ │ │
+│ │ "What size?" │ ──► │ "What crust?" │ ──► │ "Toppings?" │ ──► 🍕 │
+│ │ "Large" │ │ "Thin" │ │ "Pepperoni" │ │
+│ │ │ │ │ │ │ │
+│ └───────────────┘ └───────────────┘ └───────────────┘ │
+│ │ │ │ │
+│ ▼ ▼ ▼ │
+│ Returns function Returns function Returns the │
+│ that remembers that remembers final pizza! │
+│ size="Large" size + crust │
+│ │
+│ Each station REMEMBERS your previous choices using closures! │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+Here's that pizza order in code:
+
+```javascript
+const orderPizza = size => crust => topping => {
+ return `${size} ${crust}-crust ${topping} pizza`
+}
+
+// Full order at once
+orderPizza("Large")("Thin")("Pepperoni")
+// "Large Thin-crust Pepperoni pizza"
+
+// Or step by step
+const largeOrder = orderPizza("Large") // Remembers size
+const largeThinOrder = largeOrder("Thin") // Remembers size + crust
+const myPizza = largeThinOrder("Pepperoni") // Final pizza!
+// "Large Thin-crust Pepperoni pizza"
+
+// Create reusable "order templates"
+const orderLarge = orderPizza("Large")
+const orderLargeThin = orderLarge("Thin")
+
+orderLargeThin("Mushroom") // "Large Thin-crust Mushroom pizza"
+orderLargeThin("Hawaiian") // "Large Thin-crust Hawaiian pizza"
+```
+
+The magic is that each intermediate function "remembers" the arguments from previous calls. That's [closures](/concepts/scope-and-closures) at work!
+
+---
+
+## How Currying Works Step by Step
+
+Let's trace through exactly what happens when you call a curried function:
+
+```javascript
+const add = a => b => c => a + b + c
+
+// Step 1: Call add(1)
+const step1 = add(1)
+// Returns: b => c => 1 + b + c
+// The value 1 is "closed over" - remembered by the returned function
+
+// Step 2: Call step1(2)
+const step2 = step1(2)
+// Returns: c => 1 + 2 + c
+// Now both 1 and 2 are remembered
+
+// Step 3: Call step2(3)
+const result = step2(3)
+// Returns: 1 + 2 + 3 = 6
+// All arguments collected, computation happens!
+
+console.log(result) // 6
+```
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ HOW CURRYING EXECUTES │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ add(1)(2)(3) │
+│ │
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ add(1) │ │
+│ │ a = 1 │ │
+│ │ Returns: b => c => 1 + b + c │ │
+│ └──────────────────────────────┬──────────────────────────────────┘ │
+│ │ │
+│ ▼ │
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ (2) ← called on returned function │ │
+│ │ b = 2, a = 1 (from closure) │ │
+│ │ Returns: c => 1 + 2 + c │ │
+│ └──────────────────────────────┬──────────────────────────────────┘ │
+│ │ │
+│ ▼ │
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ (3) ← called on returned function │ │
+│ │ c = 3, b = 2, a = 1 (all from closures) │ │
+│ │ Returns: 1 + 2 + 3 = 6 │ │
+│ └─────────────────────────────────────────────────────────────────┘ │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+### The Closure Connection
+
+Currying 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.
+
+```javascript
+const multiply = a => b => a * b
+
+const double = multiply(2) // 'a' is now 2, locked in by closure
+const triple = multiply(3) // Different closure, 'a' is 3
+
+double(5) // 10 (2 * 5)
+triple(5) // 15 (3 * 5)
+double(10) // 20 (2 * 10)
+
+// 'double' and 'triple' each have their own closure
+// with their own remembered value of 'a'
+```
+
+---
+
+## Implementing a Curry Helper
+
+Writing curried functions manually works, but it's tedious for functions with many parameters. Let's build a `curry()` helper that transforms any function automatically.
+
+### Basic Curry (Two Arguments)
+
+```javascript
+function curry(fn) {
+ return function(a) {
+ return function(b) {
+ return fn(a, b)
+ }
+ }
+}
+
+// Usage
+const add = (a, b) => a + b
+const curriedAdd = curry(add)
+
+curriedAdd(1)(2) // 3
+```
+
+### Advanced Curry (Any Number of Arguments)
+
+This 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:
+
+```javascript
+function curry(fn) {
+ return function curried(...args) {
+ // If we have enough arguments, call the original function
+ if (args.length >= fn.length) {
+ return fn.apply(this, args)
+ }
+
+ // Otherwise, return a function that collects more arguments
+ return function(...nextArgs) {
+ return curried.apply(this, args.concat(nextArgs))
+ }
+ }
+}
+```
+
+Let's break down how this works:
+
+```javascript
+function sum(a, b, c) {
+ return a + b + c
+}
+
+const curriedSum = curry(sum)
+
+// All these work:
+curriedSum(1, 2, 3) // 6 - called normally
+curriedSum(1)(2)(3) // 6 - fully curried
+curriedSum(1, 2)(3) // 6 - mixed
+curriedSum(1)(2, 3) // 6 - mixed
+```
+
+
+```javascript
+// Initial call: curry(sum)
+// fn = sum, fn.length = 3
+// Returns the 'curried' function
+
+// Call: curriedSum(1)
+// args = [1], args.length (1) < fn.length (3)
+// Returns a new function that remembers [1]
+
+// Call: (previousResult)(2)
+// args = [1, 2], args.length (2) < fn.length (3)
+// Returns a new function that remembers [1, 2]
+
+// Call: (previousResult)(3)
+// args = [1, 2, 3], args.length (3) >= fn.length (3)
+// Calls sum(1, 2, 3) and returns 6
+```
+
+
+### ES6 Concise Version
+
+For those who love one-liners:
+
+```javascript
+const curry = fn =>
+ function curried(...args) {
+ return args.length >= fn.length
+ ? fn(...args)
+ : (...next) => curried(...args, ...next)
+ }
+```
+
+
+**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):
+
+```javascript
+function withRest(...args) {} // length is 0
+function withDefault(a, b = 2) {} // length is 1
+
+// Curry won't work correctly with these!
+// You'd need to specify arity manually:
+// curry(fn, expectedArgCount)
+```
+
+
+---
+
+## Currying vs Partial Application
+
+These terms are often confused, but they're different techniques:
+
+| Aspect | Currying | Partial Application |
+|--------|----------|---------------------|
+| Arguments per call | Always **one** | Any number |
+| What it returns | Chain of unary functions | Single function with some args fixed |
+| Transformation | Structural (changes function shape) | Creates specialized version |
+
+### Currying Example
+
+Currying always produces functions that take exactly one argument:
+
+```javascript
+// Curried: each call takes ONE argument
+const add = a => b => c => a + b + c
+
+add(1) // Returns: b => c => 1 + b + c
+add(1)(2) // Returns: c => 1 + 2 + c
+add(1)(2)(3) // Returns: 6
+```
+
+### Partial Application Example
+
+Partial application fixes some arguments upfront, and the resulting function takes all remaining arguments at once:
+
+```javascript
+// Partial application helper
+function partial(fn, ...presetArgs) {
+ return function(...laterArgs) {
+ return fn(...presetArgs, ...laterArgs)
+ }
+}
+
+function greet(greeting, punctuation, name) {
+ return `${greeting}, ${name}${punctuation}`
+}
+
+// Fix the first two arguments
+const greetExcitedly = partial(greet, "Hello", "!")
+
+greetExcitedly("Alice") // "Hello, Alice!"
+greetExcitedly("Bob") // "Hello, Bob!"
+
+// The returned function takes remaining args TOGETHER, not one at a time
+```
+
+### Visual Comparison
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ CURRYING VS PARTIAL APPLICATION │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Original: greet(greeting, punctuation, name) │
+│ │
+│ CURRYING: │
+│ ───────── │
+│ curriedGreet("Hello")("!")("Alice") │
+│ │ │ │ │
+│ ▼ ▼ ▼ │
+│ [1 arg] → [1 arg] → [1 arg] → result │
+│ │
+│ PARTIAL APPLICATION: │
+│ ──────────────────── │
+│ partial(greet, "Hello", "!")("Alice") │
+│ │ │ │
+│ ▼ ▼ │
+│ [2 args fixed] → [1 arg] → result │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+
+**When to use which?**
+- **Currying:** When you want maximum flexibility in how arguments are provided
+- **Partial Application:** When you want to create specialized versions of functions with some arguments preset
+
+
+---
+
+## Real-World Currying Patterns
+
+Currying isn't just a theoretical concept. Here are patterns you'll see in production code:
+
+### 1. Configurable Logging
+
+```javascript
+// Curried logger factory
+const createLogger = level => timestamp => message => {
+ const time = timestamp ? new Date().toISOString() : ''
+ console.log(`[${level}]${time ? ' ' + time : ''} ${message}`)
+}
+
+// Create specialized loggers
+const info = createLogger('INFO')(true)
+const debug = createLogger('DEBUG')(true)
+const error = createLogger('ERROR')(true)
+
+// Use them
+info('Application started') // [INFO] 2024-01-15T10:30:00.000Z Application started
+debug('Processing request') // [DEBUG] 2024-01-15T10:30:00.000Z Processing request
+error('Connection failed') // [ERROR] 2024-01-15T10:30:00.000Z Connection failed
+
+// Logger without timestamp for development
+const quickLog = createLogger('LOG')(false)
+quickLog('Quick debug message') // [LOG] Quick debug message
+```
+
+### 2. API Client Factory
+
+```javascript
+const createApiClient = baseUrl => endpoint => options => {
+ return fetch(`${baseUrl}${endpoint}`, options)
+ .then(res => res.json())
+}
+
+// Create clients for different APIs
+const githubApi = createApiClient('https://api.github.com')
+const myApi = createApiClient('https://api.myapp.com')
+
+// Create endpoint-specific fetchers
+const getGithubUser = githubApi('/users')
+const getMyAppUsers = myApi('/users')
+
+// Use them
+getGithubUser({ method: 'GET' })
+ .then(users => console.log(users))
+```
+
+### 3. Event Handler Configuration
+
+```javascript
+const handleEvent = eventType => element => callback => {
+ element.addEventListener(eventType, callback)
+
+ // Return cleanup function
+ return () => element.removeEventListener(eventType, callback)
+}
+
+// Create specialized handlers
+const onClick = handleEvent('click')
+const onHover = handleEvent('mouseenter')
+
+// Attach to elements
+const button = document.querySelector('#myButton')
+const removeClick = onClick(button)(() => console.log('Clicked!'))
+
+// Later: cleanup
+removeClick()
+```
+
+### 4. Validation Functions
+
+```javascript
+const isGreaterThan = min => value => value > min
+const isLessThan = max => value => value < max
+const hasLength = length => str => str.length === length
+
+// Create specific validators
+const isAdult = isGreaterThan(17)
+const isValidAge = isLessThan(120)
+const isValidZipCode = hasLength(5)
+
+// Use with array methods
+const ages = [15, 22, 45, 8, 67]
+const adults = ages.filter(isAdult) // [22, 45, 67]
+
+const zipCodes = ['12345', '1234', '123456', '54321']
+const validZips = zipCodes.filter(isValidZipCode) // ['12345', '54321']
+```
+
+### 5. Discount Calculator
+
+```javascript
+const applyDiscount = discountPercent => price => {
+ return price * (1 - discountPercent / 100)
+}
+
+const tenPercentOff = applyDiscount(10)
+const twentyPercentOff = applyDiscount(20)
+const blackFridayDeal = applyDiscount(50)
+
+tenPercentOff(100) // 90
+twentyPercentOff(100) // 80
+blackFridayDeal(100) // 50
+
+// Apply to multiple items
+const prices = [100, 200, 50, 75]
+const discountedPrices = prices.map(tenPercentOff) // [90, 180, 45, 67.5]
+```
+
+---
+
+## What is Function Composition?
+
+**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.
+
+In 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."
+
+```javascript
+// Individual functions
+const add10 = x => x + 10
+const multiply2 = x => x * 2
+const subtract5 = x => x - 5
+
+// Manual composition (nested calls)
+const result = subtract5(multiply2(add10(5)))
+// Step by step: 5 → 15 → 30 → 25
+
+// With a compose function
+const composed = compose(subtract5, multiply2, add10)
+composed(5) // 25
+```
+
+Why compose instead of nesting? Because this:
+
+```javascript
+addGreeting(capitalize(trim(getName(user))))
+```
+
+Becomes this:
+
+```javascript
+const processUser = compose(
+ addGreeting,
+ capitalize,
+ trim,
+ getName
+)
+processUser(user)
+```
+
+Much easier to read, modify, and test!
+
+---
+
+## The Assembly Line Analogy
+
+Think 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.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ THE ASSEMBLY LINE ANALOGY │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ RAW INPUT ──► [Station A] ──► [Station B] ──► [Station C] ──► OUTPUT │
+│ │
+│ pipe(stationA, stationB, stationC)(rawInput) │
+│ │
+│ ───────────────────────────────────────────────────────────────────── │
+│ │
+│ Example: Transform user data │
+│ │
+│ { name: " ALICE " } │
+│ │ │
+│ ▼ │
+│ ┌─────────────┐ │
+│ │ getName │ → " ALICE " │
+│ └─────────────┘ │
+│ │ │
+│ ▼ │
+│ ┌─────────────┐ │
+│ │ trim │ → "ALICE" │
+│ └─────────────┘ │
+│ │ │
+│ ▼ │
+│ ┌─────────────┐ │
+│ │ toLowerCase │ → "alice" │
+│ └─────────────┘ │
+│ │ │
+│ ▼ │
+│ Final output: "alice" │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+Each station:
+1. Takes input from the previous station
+2. Does ONE specific transformation
+3. Passes output to the next station
+
+This is exactly how composed functions work!
+
+---
+
+## compose() and pipe()
+
+There are two ways to compose functions, differing only in direction:
+
+| Function | Direction | Reads like... |
+|----------|-----------|---------------|
+| `compose(f, g, h)` | Right to left | Math: `f(g(h(x)))` |
+| `pipe(f, g, h)` | Left to right | A recipe: "first f, then g, then h" |
+
+### Implementing pipe()
+
+`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:
+
+```javascript
+const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)
+```
+
+Let's trace through it:
+
+```javascript
+const getName = obj => obj.name
+const toUpperCase = str => str.toUpperCase()
+const addExclaim = str => str + '!'
+
+const shout = pipe(getName, toUpperCase, addExclaim)
+
+shout({ name: 'alice' })
+
+// reduce trace:
+// Initial: x = { name: 'alice' }
+// Step 1: getName({ name: 'alice' }) → 'alice'
+// Step 2: toUpperCase('alice') → 'ALICE'
+// Step 3: addExclaim('ALICE') → 'ALICE!'
+// Result: 'ALICE!'
+```
+
+### Implementing compose()
+
+`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:
+
+```javascript
+const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x)
+```
+
+```javascript
+// compose processes right-to-left
+const shout = compose(addExclaim, toUpperCase, getName)
+shout({ name: 'alice' }) // 'ALICE!'
+
+// This is equivalent to:
+addExclaim(toUpperCase(getName({ name: 'alice' })))
+```
+
+### Which Should You Use?
+
+```javascript
+// These produce the same result:
+pipe(a, b, c)(x) // a first, then b, then c
+compose(c, b, a)(x) // Same! c(b(a(x)))
+```
+
+Most developers prefer `pipe` because:
+1. It reads left-to-right like English
+2. Functions are listed in execution order
+3. It's easier to follow the data flow
+
+```javascript
+// pipe: reads in order of execution
+const processUser = pipe(
+ validateInput, // First
+ sanitizeData, // Second
+ saveToDatabase, // Third
+ sendNotification // Fourth
+)
+
+// compose: reads in reverse order
+const processUser = compose(
+ sendNotification, // Fourth (but listed first)
+ saveToDatabase, // Third
+ sanitizeData, // Second
+ validateInput // First (but listed last)
+)
+```
+
+---
+
+## Building Data Pipelines
+
+Composition really shines when building data transformation pipelines:
+
+```javascript
+const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)
+
+// Individual transformation functions
+const removeSpaces = str => str.trim()
+const toLowerCase = str => str.toLowerCase()
+const splitWords = str => str.split(' ')
+const capitalizeFirst = words => words.map((w, i) =>
+ i === 0 ? w : w[0].toUpperCase() + w.slice(1)
+)
+const joinWords = words => words.join('')
+
+// Compose them into a pipeline
+const toCamelCase = pipe(
+ removeSpaces,
+ toLowerCase,
+ splitWords,
+ capitalizeFirst,
+ joinWords
+)
+
+toCamelCase(' HELLO WORLD ') // 'helloWorld'
+toCamelCase('my variable name') // 'myVariableName'
+```
+
+### Real-World Pipeline: Processing API Data
+
+```javascript
+// Transform API response into display format
+const processApiResponse = pipe(
+ // Extract data from response
+ response => response.data,
+
+ // Filter active users only
+ users => users.filter(u => u.isActive),
+
+ // Sort by name
+ users => users.sort((a, b) => a.name.localeCompare(b.name)),
+
+ // Transform to display format
+ users => users.map(u => ({
+ id: u.id,
+ displayName: `${u.firstName} ${u.lastName}`,
+ email: u.email
+ })),
+
+ // Take first 10
+ users => users.slice(0, 10)
+)
+
+// Use it
+fetch('/api/users')
+ .then(res => res.json())
+ .then(processApiResponse)
+ .then(users => renderUserList(users))
+```
+
+---
+
+## Why Currying and Composition Work Together
+
+Currying and composition are natural partners. Here's why:
+
+### The Problem: Functions with Multiple Arguments
+
+Composition works best with functions that take a single argument and return a single value. But many useful functions need multiple arguments:
+
+```javascript
+const add = (a, b) => a + b
+const multiply = (a, b) => a * b
+
+// This doesn't work!
+const addThenMultiply = pipe(add, multiply)
+addThenMultiply(1, 2) // NaN - multiply receives one value, not two
+```
+
+### The Solution: Currying
+
+Currying converts multi-argument functions into chains of single-argument functions, making them perfect for composition:
+
+```javascript
+// Curried versions
+const add = a => b => a + b
+const multiply = a => b => a * b
+
+// Now we can compose!
+const add5 = add(5) // x => 5 + x
+const double = multiply(2) // x => 2 * x
+
+const add5ThenDouble = pipe(add5, double)
+add5ThenDouble(10) // (10 + 5) * 2 = 30
+```
+
+### Data-Last Parameter Order
+
+For composition to work smoothly, the **data** should be the **last** parameter. This is called "data-last" design:
+
+```javascript
+// ❌ Data-first (hard to compose)
+const map = (array, fn) => array.map(fn)
+const filter = (array, fn) => array.filter(fn)
+
+// ✓ Data-last (easy to compose)
+const map = fn => array => array.map(fn)
+const filter = fn => array => array.filter(fn)
+
+// Now they compose beautifully
+const double = x => x * 2
+const isEven = x => x % 2 === 0
+
+const doubleEvens = pipe(
+ filter(isEven),
+ map(double)
+)
+
+doubleEvens([1, 2, 3, 4, 5, 6]) // [4, 8, 12]
+```
+
+### Point-Free Style
+
+When currying and composition combine, you can write code without explicitly mentioning the data being processed. This is called **point-free** style:
+
+```javascript
+// With explicit data parameter (pointed style)
+const processNumbers = numbers => {
+ return numbers
+ .filter(x => x > 0)
+ .map(x => x * 2)
+ .reduce((sum, x) => sum + x, 0)
+}
+
+// Point-free style (no explicit 'numbers' parameter)
+const isPositive = x => x > 0
+const double = x => x * 2
+const sum = (a, b) => a + b
+
+const processNumbers = pipe(
+ filter(isPositive),
+ map(double),
+ reduce(sum, 0)
+)
+
+// Both do the same thing:
+processNumbers([1, -2, 3, -4, 5]) // 18
+```
+
+Point-free code focuses on the transformations, not the data. It's often more declarative and easier to reason about.
+
+---
+
+## Lodash, Ramda, and Vanilla JavaScript
+
+Libraries 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.
+
+### Why Use a Library?
+
+Libraries offer features our simple implementations lack:
+
+```javascript
+import _ from 'lodash'
+
+// 1. Placeholder support
+const greet = _.curry((greeting, name) => `${greeting}, ${name}!`)
+greet(_.__, 'Alice')('Hello') // "Hello, Alice!"
+// The __ placeholder lets you skip arguments
+
+// 2. Works with variadic functions
+const sum = _.curry((...nums) => nums.reduce((a, b) => a + b, 0), 3)
+sum(1)(2)(3) // 6
+
+// 3. Auto-curried utility functions
+_.map(x => x * 2)([1, 2, 3]) // [2, 4, 6]
+// Lodash/fp provides auto-curried, data-last versions
+```
+
+### Ramda: Built for Composition
+
+[Ramda](https://ramdajs.com/) is designed from the ground up for functional programming:
+
+```javascript
+import * as R from 'ramda'
+
+// All functions are auto-curried
+R.add(1)(2) // 3
+R.add(1, 2) // 3
+
+// Data-last by default
+R.map(x => x * 2, [1, 2, 3]) // [2, 4, 6]
+R.map(x => x * 2)([1, 2, 3]) // [2, 4, 6]
+
+// Built-in compose and pipe
+const processUser = R.pipe(
+ R.prop('name'),
+ R.trim,
+ R.toLower
+)
+
+processUser({ name: ' ALICE ' }) // 'alice'
+```
+
+### Lodash/fp: Functional Lodash
+
+Lodash provides a functional programming variant:
+
+```javascript
+import fp from 'lodash/fp'
+
+// Auto-curried, data-last
+const getAdultNames = fp.pipe(
+ fp.filter(user => user.age >= 18),
+ fp.map(fp.get('name')),
+ fp.sortBy(fp.identity)
+)
+
+const users = [
+ { name: 'Charlie', age: 25 },
+ { name: 'Alice', age: 17 },
+ { name: 'Bob', age: 30 }
+]
+
+getAdultNames(users) // ['Bob', 'Charlie']
+```
+
+### Vanilla JavaScript Alternatives
+
+You don't always need a library. Here are vanilla implementations for common patterns:
+
+```javascript
+// Curry
+const curry = fn => {
+ return function curried(...args) {
+ return args.length >= fn.length
+ ? fn(...args)
+ : (...next) => curried(...args, ...next)
+ }
+}
+
+// Pipe and Compose
+const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x)
+const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x)
+
+// Partial Application
+const partial = (fn, ...presetArgs) => (...laterArgs) => fn(...presetArgs, ...laterArgs)
+
+// Data-last map and filter
+const map = fn => arr => arr.map(fn)
+const filter = fn => arr => arr.filter(fn)
+const reduce = (fn, initial) => arr => arr.reduce(fn, initial)
+```
+
+### When to Use What?
+
+| Situation | Recommendation |
+|-----------|----------------|
+| Learning/small project | Vanilla JS implementations |
+| Already using Lodash | Use `lodash/fp` for functional code |
+| Heavy functional programming | Consider Ramda |
+| Bundle size matters | Vanilla JS or tree-shakeable imports |
+| Team familiarity | Match existing codebase patterns |
+
+---
+
+## Common Currying Mistakes
+
+### Mistake #1: Forgetting Curried Functions Return Functions
+
+```javascript
+const add = a => b => a + b
+
+// ❌ Wrong: Forgot the second call
+const result = add(1)
+console.log(result) // [Function] - not a number!
+
+// ✓ Correct
+const result = add(1)(2)
+console.log(result) // 3
+```
+
+### Mistake #2: Wrong Argument Order
+
+For composition to work, data should come last:
+
+```javascript
+// ❌ Data-first: hard to compose
+const multiply = (value, factor) => value * factor
+
+// ✓ Data-last: composes well
+const multiply = factor => value => value * factor
+
+const double = multiply(2)
+const triple = multiply(3)
+
+pipe(double, triple)(5) // 30
+```
+
+### Mistake #3: Currying Functions with Rest Parameters
+
+```javascript
+function sum(...nums) {
+ return nums.reduce((a, b) => a + b, 0)
+}
+
+console.log(sum.length) // 0 - rest parameters have length 0!
+
+// Our curry won't work correctly
+const curriedSum = curry(sum)
+curriedSum(1)(2)(3) // Calls immediately with just 1!
+```
+
+**Solution:** Specify arity explicitly:
+
+```javascript
+const curryN = (fn, arity) => {
+ return function curried(...args) {
+ return args.length >= arity
+ ? fn(...args)
+ : (...next) => curried(...args, ...next)
+ }
+}
+
+const curriedSum = curryN(sum, 3)
+curriedSum(1)(2)(3) // 6
+```
+
+---
+
+## Common Composition Mistakes
+
+### Mistake #1: Type Mismatches in Pipeline
+
+Each function's output must match the next function's expected input:
+
+```javascript
+const getName = obj => obj.name // Returns string
+const getLength = arr => arr.length // Expects array!
+
+// ❌ Broken pipeline
+const broken = pipe(getName, getLength)
+broken({ name: 'Alice' }) // 5 (works by accident - string has .length)
+
+// But what if getName returns something without .length?
+const getAge = obj => obj.age // Returns number
+const getLength = arr => arr.length
+
+const reallyBroken = pipe(getAge, getLength)
+reallyBroken({ age: 25 }) // undefined - numbers don't have .length
+```
+
+### Mistake #2: Side Effects in Pipelines
+
+Composed functions should be [pure](/concepts/pure-functions). Side effects make pipelines unpredictable:
+
+```javascript
+// ❌ Side effect in pipeline
+let globalCounter = 0
+const addAndCount = x => {
+ globalCounter++ // Side effect!
+ return x + 1
+}
+
+// This is unpredictable - depends on global state
+const process = pipe(addAndCount, addAndCount)
+```
+
+### Mistake #3: Over-Composing
+
+Sometimes explicit code is clearer than a point-free pipeline:
+
+```javascript
+// ❌ Too clever - hard to understand
+const processUser = pipe(
+ prop('account'),
+ prop('settings'),
+ prop('preferences'),
+ prop('theme'),
+ defaultTo('light'),
+ eq('dark'),
+ ifElse(identity, always('🌙'), always('☀️'))
+)
+
+// ✓ Clearer
+function getThemeEmoji(user) {
+ const theme = user?.account?.settings?.preferences?.theme ?? 'light'
+ return theme === 'dark' ? '🌙' : '☀️'
+}
+```
+
+
+**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.
+
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **Currying transforms `f(a, b, c)` into `f(a)(b)(c)`** — each call takes one argument and returns a function waiting for the next
+
+2. **Currying depends on closures** — each nested function "closes over" arguments from parent functions, remembering them
+
+3. **Currying ≠ Partial Application** — currying always produces unary functions; partial application fixes some args and takes the rest together
+
+4. **Function composition combines simple functions into complex ones** — output of one becomes input of the next
+
+5. **`pipe()` flows left-to-right, `compose()` flows right-to-left** — most developers prefer pipe because it reads in execution order
+
+6. **Currying enables composition** — curried functions take one input and return one output, perfect for chaining
+
+7. **"Data-last" ordering is essential** — put the data parameter last so curried functions compose naturally
+
+8. **Point-free style focuses on transformations** — no explicit data parameters, just a chain of operations
+
+9. **Libraries like Lodash/Ramda add powerful features** — placeholders, auto-currying, and battle-tested utilities
+
+10. **Vanilla JS implementations work for most cases** — `curry`, `pipe`, and `compose` are just a few lines each
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ **Currying** transforms a function so that it takes arguments one at a time, returning a new function after each argument until all are received.
+
+ **Partial application** fixes some arguments upfront and returns a function that takes the remaining arguments together.
+
+ ```javascript
+ // Currying: one argument at a time
+ const curriedAdd = a => b => c => a + b + c
+ curriedAdd(1)(2)(3) // 6
+
+ // Partial application: fix some args, take rest together
+ const add = (a, b, c) => a + b + c
+ const partial = (fn, ...preset) => (...rest) => fn(...preset, ...rest)
+ const add1 = partial(add, 1)
+ add1(2, 3) // 6 - takes remaining args at once
+ ```
+
+
+
+ **Answer:**
+
+ ```javascript
+ function curry(fn) {
+ return function curried(...args) {
+ if (args.length >= fn.length) {
+ return fn(...args)
+ }
+ return (...nextArgs) => curried(...args, ...nextArgs)
+ }
+ }
+
+ // Usage
+ const add = (a, b, c) => a + b + c
+ const curriedAdd = curry(add)
+
+ curriedAdd(1)(2)(3) // 6
+ curriedAdd(1, 2)(3) // 6
+ curriedAdd(1)(2, 3) // 6
+ curriedAdd(1, 2, 3) // 6
+ ```
+
+
+
+ **Answer:**
+
+ Both combine functions, but in opposite directions:
+
+ - **`pipe(f, g, h)(x)`** — Left to right: `h(g(f(x)))`
+ - **`compose(f, g, h)(x)`** — Right to left: `f(g(h(x)))`
+
+ ```javascript
+ const add1 = x => x + 1
+ const double = x => x * 2
+ const square = x => x * x
+
+ // pipe: add1 first, then double, then square
+ pipe(add1, double, square)(3) // ((3+1)*2)² = 64
+
+ // compose: square first, then double, then add1
+ compose(add1, double, square)(3) // (3²*2)+1 = 19
+ ```
+
+ Most developers prefer `pipe` because functions are listed in execution order.
+
+
+
+ **Answer:**
+
+ 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.
+
+ ```javascript
+ // Without currying - can't compose
+ const add = (a, b) => a + b
+ const multiply = (a, b) => a * b
+ // How would you pipe these?
+
+ // With currying - composes naturally
+ const add = a => b => a + b
+ const multiply = a => b => a * b
+
+ const add5 = add(5)
+ const double = multiply(2)
+
+ const add5ThenDouble = pipe(add5, double)
+ add5ThenDouble(10) // 30
+ ```
+
+ The key is "data-last" ordering: configure the function first, pass data last.
+
+
+
+ **Answer:**
+
+ 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:
+
+ ```javascript
+ function sum(a) {
+ return function next(b) {
+ if (b === undefined) {
+ return a // No more arguments, return sum
+ }
+ return sum(a + b) // More arguments, keep accumulating
+ }
+ }
+
+ sum(1)(2)(3)() // 6
+ sum(1)(2)(3)(4)(5)() // 15
+ sum(10)() // 10
+ ```
+
+ Alternative using `valueOf` for implicit conversion:
+
+ ```javascript
+ function sum(a) {
+ const fn = b => sum(a + b)
+ fn.valueOf = () => a
+ return fn
+ }
+
+ +sum(1)(2)(3) // 6 (unary + triggers valueOf)
+ ```
+
+
+
+ **Answer:**
+
+ 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.
+
+ ```javascript
+ // Pointed style (explicit argument)
+ const getUpperName = user => user.name.toUpperCase()
+
+ // Point-free style (no explicit argument)
+ const getUpperName = pipe(
+ prop('name'),
+ toUpperCase
+ )
+
+ // Another example
+ // Pointed:
+ const doubleAll = numbers => numbers.map(x => x * 2)
+
+ // Point-free:
+ const doubleAll = map(x => x * 2)
+ ```
+
+ 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.
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Currying depends on closures to remember arguments between calls
+
+
+ Functions that return functions are the foundation of currying
+
+
+ Composed pipelines work best with pure, side-effect-free functions
+
+
+ Array methods that compose beautifully when curried
+
+
+
+---
+
+## Reference
+
+
+
+ Complete guide to JavaScript functions, the building blocks of currying and composition
+
+
+ Understanding closures is essential for understanding how currying preserves arguments
+
+
+ The reduce method powers our compose and pipe implementations
+
+
+ Used in compose to process functions from right to left
+
+
+
+## Articles
+
+
+
+ The definitive tutorial on currying with clear examples and an advanced curry implementation. Includes a practical logging example that shows real-world benefits.
+
+
+ Step-by-step debugger walkthrough showing exactly how pipe and compose work internally. The visual traces make the concept click.
+
+
+ Part of the "Composing Software" series. Comprehensive coverage of how currying enables composition, with trace utilities for debugging pipelines.
+
+
+ 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.
+
+
+ Index to the complete "Composing Software" series covering functional programming, composition, functors, and more in JavaScript.
+
+
+ Covers practical functional JavaScript patterns including currying and composition with approachable explanations.
+
+
+
+## Videos
+
+
+
+ Mattias Petter Johansson's entertaining explanation of currying as part of his beloved functional programming series. Great for visual learners.
+
+
+ Kyle Cook's clear, beginner-friendly walkthrough of compose and pipe with practical examples you can follow along with.
+
+
+ A beloved JSUnconf talk that explains functional programming concepts with clarity and humor. Anjana's approachable style makes abstract concepts feel tangible.
+
+
diff --git a/docs/concepts/data-structures.mdx b/docs/concepts/data-structures.mdx
new file mode 100644
index 00000000..33d2147d
--- /dev/null
+++ b/docs/concepts/data-structures.mdx
@@ -0,0 +1,1258 @@
+---
+title: "Data Structures: Organizing and Storing Data in JavaScript"
+sidebarTitle: "Data Structures: Organizing and Storing Data"
+description: "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."
+---
+
+Why 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**.
+
+```javascript
+// Array: searching gets slower as the array grows
+const users = ['alice', 'bob', 'charlie', /* ...thousands more */]
+users.includes('zara') // Has to check every element - O(n)
+
+// Object: lookup is instant regardless of size
+const userMap = { alice: 1, bob: 2, charlie: 3, /* ...thousands more */ }
+userMap['zara'] // Direct access - O(1)
+```
+
+A **data structure** is a way of organizing data so it can be used efficiently. The right structure makes your code faster and cleaner. The wrong one can make simple operations painfully slow.
+
+
+**What you'll learn in this guide:**
+- JavaScript's built-in structures: Array, Object, Map, Set, WeakMap, WeakSet
+- When to use each built-in structure
+- How to implement: Stack, Queue, Linked List, Binary Search Tree
+- Choosing the right data structure for the job
+- Common interview questions and patterns
+
+
+
+**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.
+
+
+---
+
+## What Are Data Structures?
+
+Think of data structures like different ways to organize a library. You could:
+
+- **Stack books on a table** — Easy to add/remove from the top, but finding a specific book means digging through the pile
+- **Line them up on a shelf** — Easy to browse in order, but adding a book in the middle means shifting everything
+- **Organize by category with an index** — Finding any book is fast, but you need to maintain the index
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ DATA STRUCTURE TRADE-OFFS │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ARRAY OBJECT/MAP LINKED LIST │
+│ ┌─┬─┬─┬─┬─┐ ┌────────────┐ ┌───┐ ┌───┐ │
+│ │0│1│2│3│4│ │ key: value │ │ A │──►│ B │──► │
+│ └─┴─┴─┴─┴─┘ │ key: value │ └───┘ └───┘ │
+│ └────────────┘ │
+│ ✓ Fast index access ✓ Fast key lookup ✓ Fast insert/delete │
+│ ✓ Ordered ✓ Flexible keys ✗ Slow search │
+│ ✗ Slow insert in middle ✗ No order (Object) ✗ No index access │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+Every data structure has trade-offs. Your job is to pick the one that makes your most frequent operations fast.
+
+---
+
+## JavaScript's Built-in Data Structures
+
+JavaScript gives you several data structures out of the box. Let's look at each one.
+
+### Arrays
+
+An **[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.
+
+```javascript
+const fruits = ['apple', 'banana', 'cherry']
+
+// Access by index - O(1)
+fruits[0] // 'apple'
+
+// Add to end - O(1)
+fruits.push('date') // ['apple', 'banana', 'cherry', 'date']
+
+// Remove from end - O(1)
+fruits.pop() // 'date'
+
+// Add to beginning - O(n) - shifts all elements!
+fruits.unshift('apricot') // ['apricot', 'apple', 'banana', 'cherry']
+
+// Search - O(n)
+fruits.indexOf('banana') // 3
+fruits.includes('mango') // false
+```
+
+**Time Complexity:**
+
+| Operation | Method | Complexity | Why |
+|-----------|--------|------------|-----|
+| Access by index | `arr[i]` | O(1) | Direct memory access |
+| Add/remove at end | `push()`, `pop()` | O(1) | No shifting needed |
+| Add/remove at start | `unshift()`, `shift()` | O(n) | Must shift all elements |
+| Search | `indexOf()`, `includes()` | O(n) | Must check each element |
+| Insert in middle | `splice()` | O(n) | Must shift elements after |
+
+**When to use Arrays:**
+- You need ordered data
+- You access elements by position
+- You mostly add/remove from the end
+- You need to iterate over all elements
+
+---
+
+### Objects
+
+An **[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.
+
+```javascript
+const user = {
+ name: 'Alice',
+ age: 30,
+ email: 'alice@example.com'
+}
+
+// Access - O(1)
+user.name // 'Alice'
+user['age'] // 30
+
+// Add/Update - O(1)
+user.role = 'admin'
+
+// Delete - O(1)
+delete user.email
+
+// Check if key exists - O(1)
+'name' in user // true
+user.hasOwnProperty('name') // true
+```
+
+**Limitations of Objects:**
+- Keys are converted to strings (numbers become "1", "2", etc.)
+- Objects have a prototype chain (inherited properties)
+- No built-in `.size` property
+- Property order is preserved in ES2015+, but with specific rules: integer keys are sorted numerically first, then string keys appear in insertion order
+
+**When to use Objects:**
+- Storing entity data (user profiles, settings)
+- When keys are known strings
+- Configuration objects
+- JSON data
+
+---
+
+### Map
+
+A **[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.
+
+```javascript
+const map = new Map()
+
+// Keys can be ANY type
+map.set('string', 'works')
+map.set(123, 'number key')
+map.set({ id: 1 }, 'object key')
+map.set(true, 'boolean key')
+
+// Access - O(1)
+map.get('string') // 'works'
+map.get(123) // 'number key'
+
+// Size is built-in
+map.size // 4
+
+// Check existence - O(1)
+map.has('string') // true
+
+// Delete - O(1)
+map.delete(123)
+
+// Iteration (maintains insertion order)
+for (const [key, value] of map) {
+ console.log(key, value)
+}
+```
+
+**Map vs Object:**
+
+| Feature | Map | Object |
+|---------|-----|--------|
+| Key types | Any | String or Symbol |
+| Order | Guaranteed insertion order | Preserved (integer keys sorted first) |
+| Size | `map.size` | `Object.keys(obj).length` |
+| Iteration | Directly iterable | Need `Object.keys()` |
+| Performance | Better for frequent add/delete | Better for static data |
+| Prototype | None | Has prototype chain |
+
+**When to use Map:**
+- Keys aren't strings (objects, functions, etc.)
+- You need to know the size frequently
+- You add/delete keys often
+- Order matters
+
+```javascript
+// Common use: counting occurrences
+function countWords(text) {
+ const words = text.toLowerCase().split(/\s+/)
+ const counts = new Map()
+
+ for (const word of words) {
+ counts.set(word, (counts.get(word) || 0) + 1)
+ }
+
+ return counts
+}
+
+countWords('the cat and the dog')
+// Map { 'the' => 2, 'cat' => 1, 'and' => 1, 'dog' => 1 }
+```
+
+---
+
+### Set
+
+A **[Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)** stores unique values. Duplicates are automatically ignored.
+
+```javascript
+const set = new Set()
+
+// Add values - O(1)
+set.add(1)
+set.add(2)
+set.add(2) // Ignored - already exists
+set.add('hello')
+
+set.size // 3 (not 4!)
+
+// Check existence - O(1)
+set.has(2) // true
+
+// Delete - O(1)
+set.delete(1)
+
+// Iteration
+for (const value of set) {
+ console.log(value)
+}
+```
+
+**The classic use case: removing duplicates**
+
+```javascript
+const numbers = [1, 2, 2, 3, 3, 3, 4]
+const unique = [...new Set(numbers)] // [1, 2, 3, 4]
+```
+
+**Set Operations (ES2024+):**
+
+
+These 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.
+
+
+```javascript
+const a = new Set([1, 2, 3])
+const b = new Set([2, 3, 4])
+
+// Union: elements in either set
+a.union(b) // Set {1, 2, 3, 4}
+
+// Intersection: elements in both sets
+a.intersection(b) // Set {2, 3}
+
+// Difference: elements in a but not in b
+a.difference(b) // Set {1}
+
+// Symmetric difference: elements in either but not both
+a.symmetricDifference(b) // Set {1, 4}
+
+// Subset check
+new Set([1, 2]).isSubsetOf(a) // true
+```
+
+**When to use Set:**
+- You need unique values
+- You check "does this exist?" frequently
+- Removing duplicates from arrays
+- Tracking visited items
+
+---
+
+### WeakMap and WeakSet
+
+
+
+**[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.
+
+**WeakMap:**
+- Keys must be objects (or non-registered symbols)
+- If the key object has no other references, it gets garbage collected
+- Not iterable (no `.keys()`, `.values()`, `.forEach()`)
+- No `.size` property
+
+```javascript
+const privateData = new WeakMap()
+
+class User {
+ constructor(name, password) {
+ this.name = name
+ // Store private data that can't be accessed externally
+ privateData.set(this, { password })
+ }
+
+ checkPassword(input) {
+ return privateData.get(this).password === input
+ }
+}
+
+const user = new User('Alice', 'secret123')
+user.name // 'Alice'
+user.password // undefined - it's private!
+user.checkPassword('secret123') // true
+
+// When 'user' is garbage collected, the private data is too
+```
+
+**WeakSet:**
+- Values must be objects
+- Useful for tracking which objects have been processed
+
+```javascript
+const processed = new WeakSet()
+
+function processOnce(obj) {
+ if (processed.has(obj)) {
+ return // Already processed
+ }
+
+ processed.add(obj)
+ // Do expensive processing...
+}
+```
+
+**When to use Weak versions:**
+- Caching computed data for objects
+- Storing private instance data
+- Tracking objects without preventing garbage collection
+
+
+
+---
+
+## Implementing Common Data Structures
+
+JavaScript doesn't have built-in Stack, Queue, or Linked List classes, but they're easy to implement and important to understand.
+
+### Stack (LIFO)
+
+A **Stack** follows Last-In-First-Out: the last item added is the first removed. Think of a stack of plates.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ STACK (LIFO) │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ push(4) pop() │
+│ │ │ │
+│ ▼ ▼ │
+│ ┌───┐ ┌───┐ │
+│ │ 4 │ ◄─ top │ │ │
+│ ├───┤ ├───┤ │
+│ │ 3 │ │ 3 │ ◄─ top │
+│ ├───┤ ├───┤ │
+│ │ 2 │ │ 2 │ │
+│ ├───┤ ├───┤ │
+│ │ 1 │ │ 1 │ │
+│ └───┘ └───┘ │
+│ │
+│ "Last in, first out" - like a stack of plates │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Real-world uses:**
+- Browser history (back button)
+- Undo/redo functionality
+- Function call stack
+- Expression evaluation (parentheses matching)
+
+**Implementation:**
+
+```javascript
+class Stack {
+ constructor() {
+ this.items = []
+ }
+
+ push(item) {
+ this.items.push(item)
+ }
+
+ pop() {
+ return this.items.pop()
+ }
+
+ peek() {
+ return this.items[this.items.length - 1]
+ }
+
+ isEmpty() {
+ return this.items.length === 0
+ }
+
+ size() {
+ return this.items.length
+ }
+}
+
+// Usage
+const stack = new Stack()
+stack.push(1)
+stack.push(2)
+stack.push(3)
+stack.peek() // 3 (look at top without removing)
+stack.pop() // 3
+stack.pop() // 2
+stack.size() // 1
+```
+
+**Time Complexity:** All operations are O(1).
+
+---
+
+### Queue (FIFO)
+
+A **Queue** follows First-In-First-Out: the first item added is the first removed. Think of a line at a store.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ QUEUE (FIFO) │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ enqueue(4) dequeue() │
+│ │ │ │
+│ ▼ ▼ │
+│ ┌───┬───┬───┬───┐ ┌───┬───┬───┐ │
+│ │ 4 │ 3 │ 2 │ 1 │ ───────────────────────► │ 4 │ 3 │ 2 │ │
+│ └───┴───┴───┴───┘ └───┴───┴───┘ │
+│ back front back front │
+│ │
+│ "First in, first out" - like a line at a store │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Real-world uses:**
+- Task scheduling
+- Print queue
+- BFS graph traversal
+- Message queues
+
+**Implementation:**
+
+```javascript
+class Queue {
+ constructor() {
+ this.items = []
+ }
+
+ enqueue(item) {
+ this.items.push(item)
+ }
+
+ dequeue() {
+ return this.items.shift() // Note: O(n) with arrays!
+ }
+
+ front() {
+ return this.items[0]
+ }
+
+ isEmpty() {
+ return this.items.length === 0
+ }
+
+ size() {
+ return this.items.length
+ }
+}
+
+// Usage
+const queue = new Queue()
+queue.enqueue('first')
+queue.enqueue('second')
+queue.enqueue('third')
+queue.dequeue() // 'first'
+queue.front() // 'second'
+```
+
+
+**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.
+
+
+---
+
+### Linked List
+
+A **Linked List** is a chain of nodes where each node points to the next. Unlike arrays, elements aren't stored in contiguous memory.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ LINKED LIST │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ head tail │
+│ │ │ │
+│ ▼ ▼ │
+│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
+│ │ value: 1 │ │ value: 2 │ │ value: 3 │ │ value: 4 │ │
+│ │ next: ───────► │ next: ───────► │ next: ───────► │ next: null│ │
+│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
+│ │
+│ Nodes can be anywhere in memory - connected by references │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Linked List vs Array:**
+
+| Operation | Array | Linked List |
+|-----------|-------|-------------|
+| Access by index | O(1) | O(n) |
+| Insert at beginning | O(n) | O(1) |
+| Insert at end | O(1) | O(1) with tail pointer |
+| Insert in middle | O(n) | O(1) if you have the node |
+| Search | O(n) | O(n) |
+
+**Implementation:**
+
+```javascript
+class Node {
+ constructor(value) {
+ this.value = value
+ this.next = null
+ }
+}
+
+class LinkedList {
+ constructor() {
+ this.head = null
+ this.size = 0
+ }
+
+ // Add to beginning - O(1)
+ prepend(value) {
+ const node = new Node(value)
+ node.next = this.head
+ this.head = node
+ this.size++
+ }
+
+ // Add to end - O(n)
+ append(value) {
+ const node = new Node(value)
+
+ if (!this.head) {
+ this.head = node
+ } else {
+ let current = this.head
+ while (current.next) {
+ current = current.next
+ }
+ current.next = node
+ }
+ this.size++
+ }
+
+ // Find a value - O(n)
+ find(value) {
+ let current = this.head
+ while (current) {
+ if (current.value === value) {
+ return current
+ }
+ current = current.next
+ }
+ return null
+ }
+
+ // Convert to array for easy viewing
+ toArray() {
+ const result = []
+ let current = this.head
+ while (current) {
+ result.push(current.value)
+ current = current.next
+ }
+ return result
+ }
+}
+
+// Usage
+const list = new LinkedList()
+list.prepend(1)
+list.append(2)
+list.append(3)
+list.prepend(0)
+list.toArray() // [0, 1, 2, 3]
+list.find(2) // Node { value: 2, next: Node }
+```
+
+**When to use Linked Lists:**
+- Frequent insertions/deletions at the beginning
+- You don't need random access by index
+- Implementing queues (for O(1) dequeue)
+
+---
+
+### Binary Search Tree
+
+A **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.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ BINARY SEARCH TREE │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ ┌────┐ │
+│ │ 10 │ ◄─ root │
+│ └────┘ │
+│ / \ │
+│ ┌────┐ ┌────┐ │
+│ │ 5 │ │ 15 │ │
+│ └────┘ └────┘ │
+│ / \ \ │
+│ ┌────┐ ┌────┐ ┌────┐ │
+│ │ 3 │ │ 7 │ │ 20 │ │
+│ └────┘ └────┘ └────┘ │
+│ │
+│ Rule: left child < parent < right child │
+│ This makes searching fast: just go left or right! │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Time Complexity:**
+
+| Operation | Average | Worst (unbalanced) |
+|-----------|---------|-------------------|
+| Search | O(log n) | O(n) |
+| Insert | O(log n) | O(n) |
+| Delete | O(log n) | O(n) |
+
+**Implementation:**
+
+```javascript
+class TreeNode {
+ constructor(value) {
+ this.value = value
+ this.left = null
+ this.right = null
+ }
+}
+
+class BinarySearchTree {
+ constructor() {
+ this.root = null
+ }
+
+ insert(value) {
+ const node = new TreeNode(value)
+
+ if (!this.root) {
+ this.root = node
+ return
+ }
+
+ let current = this.root
+ while (true) {
+ if (value < current.value) {
+ // Go left
+ if (!current.left) {
+ current.left = node
+ return
+ }
+ current = current.left
+ } else {
+ // Go right
+ if (!current.right) {
+ current.right = node
+ return
+ }
+ current = current.right
+ }
+ }
+ }
+
+ search(value) {
+ let current = this.root
+
+ while (current) {
+ if (value === current.value) {
+ return current
+ }
+ current = value < current.value ? current.left : current.right
+ }
+
+ return null
+ }
+
+ // In-order traversal: left, root, right (gives sorted order)
+ inOrder(node = this.root, result = []) {
+ if (node) {
+ this.inOrder(node.left, result)
+ result.push(node.value)
+ this.inOrder(node.right, result)
+ }
+ return result
+ }
+}
+
+// Usage
+const bst = new BinarySearchTree()
+bst.insert(10)
+bst.insert(5)
+bst.insert(15)
+bst.insert(3)
+bst.insert(7)
+bst.insert(20)
+
+bst.search(7) // TreeNode { value: 7, ... }
+bst.search(100) // null
+bst.inOrder() // [3, 5, 7, 10, 15, 20] - sorted!
+```
+
+**When to use BST:**
+- You need fast search, insert, and delete (O(log n) average)
+- Data needs to stay sorted
+- Implementing autocomplete, spell checkers
+
+---
+
+### Graph
+
+
+
+A **Graph** consists of nodes (vertices) connected by edges. Think social networks (people connected by friendships) or maps (cities connected by roads).
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ GRAPH │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ A ─────── B │
+│ /│\ │ │
+│ / │ \ │ │
+│ / │ \ │ │
+│ C │ D ────┘ │
+│ \ │ / │
+│ \ │ / │
+│ \│/ │
+│ E │
+│ │
+│ Adjacency List representation: │
+│ A: [B, C, D, E] │
+│ B: [A, D] │
+│ C: [A, E] │
+│ ... │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+**Basic Implementation (Adjacency List):**
+
+```javascript
+class Graph {
+ constructor() {
+ this.adjacencyList = new Map()
+ }
+
+ addVertex(vertex) {
+ if (!this.adjacencyList.has(vertex)) {
+ this.adjacencyList.set(vertex, [])
+ }
+ }
+
+ addEdge(v1, v2) {
+ this.adjacencyList.get(v1).push(v2)
+ this.adjacencyList.get(v2).push(v1) // For undirected graph
+ }
+
+ // Breadth-First Search - uses Queue (FIFO)
+ bfs(start) {
+ const visited = new Set()
+ const queue = [start]
+ const result = []
+
+ while (queue.length) {
+ const vertex = queue.shift()
+ if (visited.has(vertex)) continue
+
+ visited.add(vertex)
+ result.push(vertex)
+
+ for (const neighbor of this.adjacencyList.get(vertex)) {
+ if (!visited.has(neighbor)) {
+ queue.push(neighbor)
+ }
+ }
+ }
+
+ return result
+ }
+
+ // Depth-First Search - uses Stack (LIFO) via recursion
+ dfs(start, visited = new Set(), result = []) {
+ if (visited.has(start)) return result
+
+ visited.add(start)
+ result.push(start)
+
+ for (const neighbor of this.adjacencyList.get(start)) {
+ this.dfs(neighbor, visited, result)
+ }
+
+ return result
+ }
+}
+
+// Usage
+const graph = new Graph()
+graph.addVertex('A')
+graph.addVertex('B')
+graph.addVertex('C')
+graph.addEdge('A', 'B')
+graph.addEdge('A', 'C')
+graph.addEdge('B', 'C')
+graph.bfs('A') // ['A', 'B', 'C'] - level by level
+graph.dfs('A') // ['A', 'B', 'C'] - goes deep first
+```
+
+**Real-world uses:**
+- Social networks (friend connections)
+- Maps and navigation (shortest path)
+- Recommendation systems
+- Dependency resolution (package managers)
+
+
+
+---
+
+## Choosing the Right Data Structure
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ WHICH DATA STRUCTURE SHOULD I USE? │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Need ordered data with index access? │
+│ └──► ARRAY │
+│ │
+│ Need key-value pairs with string keys? │
+│ └──► OBJECT (static data) or MAP (dynamic) │
+│ │
+│ Need key-value with any type as key? │
+│ └──► MAP │
+│ │
+│ Need unique values only? │
+│ └──► SET │
+│ │
+│ Need LIFO (last in, first out)? │
+│ └──► STACK │
+│ │
+│ Need FIFO (first in, first out)? │
+│ └──► QUEUE │
+│ │
+│ Need fast insert/delete at beginning? │
+│ └──► LINKED LIST │
+│ │
+│ Need fast search + sorted data? │
+│ └──► BINARY SEARCH TREE │
+│ │
+│ Modeling relationships/connections? │
+│ └──► GRAPH │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+| Use Case | Best Structure | Why |
+|----------|----------------|-----|
+| Todo list | Array | Ordered, index access |
+| User settings | Object | String keys, static |
+| Word frequency counter | Map | Easy increment, any key |
+| Tag system | Set | Unique values |
+| Browser back button | Stack | LIFO |
+| Task scheduler | Queue | FIFO |
+| Playlist with prev/next | Linked List (doubly) | O(1) traversal |
+| Dictionary/autocomplete | Trie | Fast prefix search |
+| Social network | Graph | Connections |
+
+---
+
+## Common Interview Questions
+
+Interview questions often test your understanding of data structures. Here are patterns you'll encounter:
+
+
+
+ **Problem:** Find two numbers in an array that add up to a target.
+
+ **Approach:** Use a Map to store numbers you've seen. For each number, check if `target - number` exists in the Map.
+
+ ```javascript
+ function twoSum(nums, target) {
+ const seen = new Map()
+
+ for (let i = 0; i < nums.length; i++) {
+ const complement = target - nums[i]
+
+ if (seen.has(complement)) {
+ return [seen.get(complement), i]
+ }
+
+ seen.set(nums[i], i)
+ }
+
+ return []
+ }
+
+ twoSum([2, 7, 11, 15], 9) // [0, 1]
+ ```
+
+ **Why Map?** O(1) lookup turns O(n²) brute force into O(n).
+
+
+
+ **Problem:** Check if a string of brackets is valid: `()[]{}`.
+
+ **Approach:** Push opening brackets onto stack. When you see a closing bracket, pop and check if it matches.
+
+ ```javascript
+ function isValid(s) {
+ const stack = []
+ const pairs = { ')': '(', ']': '[', '}': '{' }
+
+ for (const char of s) {
+ if (char in pairs) {
+ // Closing bracket - check if it matches
+ if (stack.pop() !== pairs[char]) {
+ return false
+ }
+ } else {
+ // Opening bracket - push to stack
+ stack.push(char)
+ }
+ }
+
+ return stack.length === 0
+ }
+
+ isValid('([{}])') // true
+ isValid('([)]') // false
+ ```
+
+
+
+ **Problem:** Reverse a linked list.
+
+ **Approach:** Keep track of previous, current, and next. Reverse pointers as you go.
+
+ ```javascript
+ function reverseList(head) {
+ let prev = null
+ let current = head
+
+ while (current) {
+ const next = current.next // Save next
+ current.next = prev // Reverse pointer
+ prev = current // Move prev forward
+ current = next // Move current forward
+ }
+
+ return prev // New head
+ }
+ ```
+
+ **Key insight:** You need three pointers to avoid losing references.
+
+
+
+ **Problem:** Determine if a linked list has a cycle.
+
+ **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.
+
+ ```javascript
+ function hasCycle(head) {
+ let slow = head
+ let fast = head
+
+ while (fast && fast.next) {
+ slow = slow.next
+ fast = fast.next.next
+
+ if (slow === fast) {
+ return true // They met - cycle exists
+ }
+ }
+
+ return false // Fast reached end - no cycle
+ }
+ ```
+
+ **Why this works:** In a cycle, the fast pointer will eventually "lap" the slow pointer.
+
+
+
+ **Problem:** Find the maximum depth of a binary tree.
+
+ **Approach:** Recursively find the depth of left and right subtrees, take the max.
+
+ ```javascript
+ function maxDepth(root) {
+ if (!root) return 0
+
+ const leftDepth = maxDepth(root.left)
+ const rightDepth = maxDepth(root.right)
+
+ return Math.max(leftDepth, rightDepth) + 1
+ }
+ ```
+
+ **Base case:** Empty tree has depth 0.
+
+
+
+ **Problem:** Implement a queue using only stacks.
+
+ **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.
+
+ ```javascript
+ class QueueFromStacks {
+ constructor() {
+ this.stack1 = [] // For enqueue
+ this.stack2 = [] // For dequeue
+ }
+
+ enqueue(item) {
+ this.stack1.push(item)
+ }
+
+ dequeue() {
+ if (this.stack2.length === 0) {
+ // Pour stack1 into stack2
+ while (this.stack1.length) {
+ this.stack2.push(this.stack1.pop())
+ }
+ }
+ return this.stack2.pop()
+ }
+ }
+ ```
+
+ **Amortized O(1):** Each element is moved at most twice.
+
+
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **Arrays** are great for ordered data with index access. Push/pop are O(1), but shift/unshift are O(n).
+
+2. **Objects** store string-keyed data. Use them for static configuration and entity data.
+
+3. **Map** is the better choice when keys aren't strings, you need `.size`, or you add/delete frequently.
+
+4. **Set** stores unique values. The `[...new Set(arr)]` trick removes duplicates instantly.
+
+5. **Stack (LIFO)** is perfect for undo/redo, parsing expressions, and DFS traversal.
+
+6. **Queue (FIFO)** is ideal for task scheduling and BFS traversal. Use a linked list for O(1) dequeue.
+
+7. **Linked Lists** excel at insertions/deletions but lack random access. Use when you frequently modify the beginning.
+
+8. **Binary Search Trees** give O(log n) search/insert/delete on average. They keep data sorted.
+
+9. **Choose based on your most frequent operation.** What makes one structure fast makes another slow.
+
+10. **Interview tip:** When you need O(1) lookup, think Map or Set. When you need to track order of operations, think Stack or Queue.
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ Use Map when:
+ - Keys are not strings (objects, numbers, etc.)
+ - You need to know the size frequently (`.size` vs `Object.keys().length`)
+ - You add/delete keys often (Map is optimized for this)
+ - You need guaranteed insertion order
+ - You want to avoid prototype chain issues
+
+ Use Object when:
+ - Keys are known strings
+ - You're working with JSON data
+ - You need object destructuring or spread syntax
+
+
+
+ **Answer:**
+
+ `pop()` removes from the end. No other elements need to move.
+
+ `shift()` removes from the beginning. Every remaining element must be re-indexed:
+ - Element at index 1 moves to 0
+ - Element at index 2 moves to 1
+ - ...and so on
+
+ This is why Queue implementations with arrays have O(n) dequeue. For O(1), use a linked list or object with head/tail pointers.
+
+
+
+ **Answer:**
+
+ **Stack (LIFO):** Last In, First Out
+ - Like a stack of plates - you take from the top
+ - `push()` and `pop()` operate on the same end
+ - Use for: undo/redo, back button, recursion
+
+ **Queue (FIFO):** First In, First Out
+ - Like a line at a store - first person in line is served first
+ - `enqueue()` adds to back, `dequeue()` removes from front
+ - Use for: task scheduling, BFS, print queues
+
+
+
+ **Answer:**
+
+ Linked List wins when:
+ - You frequently insert/delete at the beginning (O(1) vs O(n))
+ - You don't need random access by index
+ - You're implementing a queue (O(1) dequeue)
+ - Memory is fragmented (nodes can be anywhere)
+
+ Array wins when:
+ - You need index-based access
+ - You iterate sequentially often
+ - You mostly add/remove from the end
+ - You need `.length`, `.map()`, `.filter()`, etc.
+
+
+
+ **Answer:**
+
+ BSTs use the rule: left < parent < right. This means:
+
+ - To find a value, compare with root
+ - If smaller, go left; if larger, go right
+ - Each comparison eliminates half the remaining nodes
+
+ This gives O(log n) search, insert, and delete (on average).
+
+ **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.
+
+
+
+ **Answer:**
+
+ The cleanest way is with Set:
+
+ ```javascript
+ const unique = [...new Set(array)]
+ ```
+
+ This works because:
+ 1. `new Set(array)` creates a Set (which only keeps unique values)
+ 2. `[...set]` spreads the Set back into an array
+
+ Time complexity: O(n) - each element is processed once.
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Understanding time complexity helps you choose the right data structure
+
+
+ The class syntax used to implement data structures
+
+
+ Array methods like map, filter, and reduce
+
+
+ Essential for tree and graph traversal algorithms
+
+
+
+---
+
+## Reference
+
+
+
+ Complete reference for JavaScript arrays
+
+
+ Documentation for Object methods and properties
+
+
+ Guide to the Map collection type
+
+
+ Documentation for Set and its new ES2024 methods
+
+
+ When to use WeakMap for memory management
+
+
+ MDN's overview of JavaScript data types and structures
+
+
+
+## Articles
+
+
+
+ The clearest explanation of Map and Set with interactive examples. Covers WeakMap and WeakSet too.
+
+
+ Oleksii Trekhleb's legendary GitHub repo with implementations of every data structure and algorithm in JavaScript. Over 180k stars for good reason.
+
+
+ freeCodeCamp's practical guide covering arrays through graphs with real-world examples you can follow along with.
+
+
+ Jamie Kyle's annotated source code explaining data structures in ~200 lines. Perfect if you learn by reading well-commented code.
+
+
+
+## Videos
+
+
+
+ freeCodeCamp's complete 8-hour course covering everything from Big O to graph algorithms. Great for interview prep.
+
+
+ Academind's beginner-friendly introduction focusing on when and why to use each structure, not just how.
+
+
+ William Fiset's comprehensive course with animations that make complex structures like trees and graphs click.
+
+
diff --git a/docs/concepts/design-patterns.mdx b/docs/concepts/design-patterns.mdx
new file mode 100644
index 00000000..c6cf3578
--- /dev/null
+++ b/docs/concepts/design-patterns.mdx
@@ -0,0 +1,1122 @@
+---
+title: "Design Patterns: Reusable Solutions to Common Problems in JavaScript"
+sidebarTitle: "Design Patterns: Reusable Solutions"
+description: "Learn JavaScript design patterns like Module, Singleton, Observer, Factory, Proxy, and Decorator. Understand when to use each pattern and avoid common pitfalls."
+---
+
+Ever find yourself solving the same problem over and over? What if experienced developers already figured out the best solutions to these recurring challenges?
+
+```javascript
+// The Observer pattern — notify multiple listeners when something happens
+const newsletter = {
+ subscribers: [],
+
+ subscribe(callback) {
+ this.subscribers.push(callback)
+ },
+
+ publish(article) {
+ this.subscribers.forEach(callback => callback(article))
+ }
+}
+
+// Anyone can subscribe
+newsletter.subscribe(article => console.log(`New article: ${article}`))
+newsletter.subscribe(article => console.log(`Saving "${article}" for later`))
+
+// When we publish, all subscribers get notified
+newsletter.publish("Design Patterns in JavaScript")
+// "New article: Design Patterns in JavaScript"
+// "Saving "Design Patterns in JavaScript" for later"
+```
+
+**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.
+
+
+**What you'll learn in this guide:**
+- What design patterns are and why they matter
+- The Module pattern for organizing code with private state
+- The Singleton pattern (and why it's often unnecessary in JavaScript)
+- The Factory pattern for creating objects dynamically
+- The Observer pattern for event-driven programming
+- The Proxy pattern for controlling object access
+- The Decorator pattern for adding behavior without modification
+- How to choose the right pattern for your problem
+
+
+
+**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.
+
+
+---
+
+## The Toolkit Analogy
+
+Think 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.
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ DESIGN PATTERNS TOOLKIT │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ CREATIONAL STRUCTURAL BEHAVIORAL │
+│ ─────────── ────────── ────────── │
+│ How objects How objects How objects │
+│ are created are composed communicate │
+│ │
+│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
+│ │ Singleton │ │ Proxy │ │ Observer │ │
+│ │ Factory │ │ Decorator │ │ │ │
+│ └─────────────┘ └─────────────┘ └─────────────┘ │
+│ │
+│ Use when you need Use when you need Use when objects │
+│ to control object to wrap or extend need to react to │
+│ creation objects changes in others │
+│ │
+│ ┌─────────────────────────────────────────────────────────────────┐ │
+│ │ MODULE (JS-specific) — Encapsulates code with private state │ │
+│ └─────────────────────────────────────────────────────────────────┘ │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+You 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.
+
+---
+
+## What Are Design Patterns?
+
+Design patterns are typical solutions to commonly occurring problems in software design. The term was popularized by the "Gang of Four" (GoF) in their 1994 book *Design Patterns: Elements of Reusable Object-Oriented Software*. They catalogued 23 patterns that developers kept reinventing.
+
+### Why JavaScript Is Different
+
+The original GoF patterns were written for languages like C++ and Smalltalk. JavaScript is different:
+
+| Feature | Impact on Patterns |
+|---------|-------------------|
+| **First-class functions** | Many patterns simplify to just passing functions around |
+| **Prototypal inheritance** | No need for complex class hierarchies |
+| **ES Modules** | Built-in module system replaces manual Module pattern |
+| **Dynamic typing** | No need for interface abstractions |
+| **Closures** | Natural way to create private state |
+
+This 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.
+
+### The Three Categories
+
+The original GoF patterns are grouped into three categories:
+
+1. **Creational Patterns** — Control how objects are created
+ - Singleton, Factory Method, Abstract Factory, Builder, Prototype
+
+2. **Structural Patterns** — Control how objects are composed
+ - Proxy, Decorator, Adapter, Facade, Bridge, Composite, Flyweight
+
+3. **Behavioral Patterns** — Control how objects communicate
+ - Observer, Strategy, Command, Mediator, Iterator, State, and others
+
+
+**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.
+
+
+We'll cover six patterns that are particularly useful in JavaScript: **Module** (JS-specific), **Singleton**, **Factory**, **Observer**, **Proxy**, and **Decorator**.
+
+---
+
+## The Module Pattern
+
+The **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.
+
+### ES6 Modules: The Modern Approach
+
+Each file is its own module. Variables are private unless you [`export`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) them:
+
+```javascript
+// counter.js — A module with private state
+let count = 0 // Private — not exported, not accessible outside
+
+export function increment() {
+ count++
+ return count
+}
+
+export function decrement() {
+ count--
+ return count
+}
+
+export function getCount() {
+ return count
+}
+
+// main.js — Using the module
+import { increment, getCount } from './counter.js'
+
+increment()
+increment()
+console.log(getCount()) // 2
+
+// Trying to access private state
+// console.log(count) // ReferenceError: count is not defined
+```
+
+### The Classic IIFE Module Pattern
+
+Before ES6, developers used closures to create modules:
+
+```javascript
+// The revealing module pattern using IIFE
+const Counter = (function() {
+ // Private variables and functions
+ let count = 0
+
+ function logChange(action) {
+ console.log(`Counter ${action}: ${count}`)
+ }
+
+ // Public API — "revealed" by returning an object
+ return {
+ increment() {
+ count++
+ logChange('incremented')
+ return count
+ },
+ decrement() {
+ count--
+ logChange('decremented')
+ return count
+ },
+ getCount() {
+ return count
+ }
+ }
+})()
+
+Counter.increment() // "Counter incremented: 1"
+Counter.increment() // "Counter incremented: 2"
+console.log(Counter.getCount()) // 2
+
+// Private members are truly private
+console.log(Counter.count) // undefined
+console.log(Counter.logChange) // undefined
+```
+
+### When to Use the Module Pattern
+
+
+
+ Group related functions and data together. A `UserService` module might contain `login()`, `logout()`, `getCurrentUser()`, and private token storage.
+
+
+
+ Expose only what consumers need. Internal helper functions, validation logic, and caching mechanisms stay private.
+
+
+
+ Instead of 50 global functions, you have one module export. This prevents naming collisions with other code.
+
+
+
+
+**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.
+
+
+---
+
+## The Singleton Pattern
+
+The **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.
+
+### JavaScript Implementation
+
+```javascript
+// Singleton using Object.freeze — immutable configuration
+const Config = {
+ apiUrl: 'https://api.example.com',
+ timeout: 5000,
+ debug: false
+}
+
+Object.freeze(Config) // Prevent all modifications
+
+// Usage anywhere in your app
+console.log(Config.apiUrl) // "https://api.example.com"
+
+// Attempting to modify throws an error in strict mode (silently fails otherwise)
+Config.apiUrl = 'https://evil.com'
+console.log(Config.apiUrl) // Still "https://api.example.com"
+
+Config.debug = true
+console.log(Config.debug) // Still false — frozen objects are immutable
+```
+
+### Class-Based Singleton
+
+```javascript
+let instance = null
+
+class Database {
+ constructor() {
+ if (instance) {
+ return instance // Return existing instance
+ }
+
+ this.connection = null
+ instance = this
+ }
+
+ connect(url) {
+ if (!this.connection) {
+ this.connection = `Connected to ${url}`
+ console.log(this.connection)
+ }
+ return this.connection
+ }
+}
+
+const db1 = new Database()
+const db2 = new Database()
+
+console.log(db1 === db2) // true — Same instance!
+
+db1.connect('mongodb://localhost') // "Connected to mongodb://localhost"
+db2.connect('mongodb://other') // Returns same connection, doesn't reconnect
+```
+
+### Why Singleton Is Often an Anti-Pattern in JavaScript
+
+Here's the thing: **Singletons are often unnecessary in JavaScript**. Here's why:
+
+```javascript
+// ES Modules are already singletons!
+// config.js
+export const config = {
+ apiUrl: 'https://api.example.com',
+ timeout: 5000
+}
+
+// main.js
+import { config } from './config.js'
+
+// other.js
+import { config } from './config.js'
+
+// Both files get the SAME object — modules are cached!
+```
+
+
+**Problems with Singletons:**
+
+1. **Testing difficulties** — Tests share the same instance, making isolation hard
+2. **Hidden dependencies** — Code that uses a Singleton has an implicit dependency
+3. **Tight coupling** — Components become coupled to a specific implementation
+4. **ES Modules already do this** — Module exports are cached; you get the same object every time
+
+**Better alternatives:** Dependency injection, React Context, or simply exporting an object from a module.
+
+
+### When Singletons Make Sense
+
+Despite the caveats, Singletons can be appropriate for:
+- **Logging services** — One logger instance for the entire app
+- **Configuration objects** — App-wide settings that shouldn't change
+- **Connection pools** — Managing a single pool of database connections
+
+
+
+ Detailed explanation with pros, cons, and implementation in multiple languages
+
+
+
+---
+
+## The Factory Pattern
+
+The **Factory pattern** creates objects without exposing the creation logic. Instead of using `new` directly, you call a factory function that returns the appropriate object. This centralizes object creation and makes it easy to change how objects are created without updating every call site.
+
+```javascript
+// Factory function — creates different user types
+function createUser(type, name) {
+ const baseUser = {
+ name,
+ createdAt: new Date(),
+ greet() {
+ return `Hi, I'm ${this.name}`
+ }
+ }
+
+ switch (type) {
+ case 'admin':
+ return {
+ ...baseUser,
+ role: 'admin',
+ permissions: ['read', 'write', 'delete', 'manage-users'],
+ promote(user) {
+ console.log(`${this.name} promoted ${user.name}`)
+ }
+ }
+
+ case 'editor':
+ return {
+ ...baseUser,
+ role: 'editor',
+ permissions: ['read', 'write']
+ }
+
+ case 'viewer':
+ default:
+ return {
+ ...baseUser,
+ role: 'viewer',
+ permissions: ['read']
+ }
+ }
+}
+
+// Usage — no need to know the internal structure
+const admin = createUser('admin', 'Alice')
+const editor = createUser('editor', 'Bob')
+const viewer = createUser('viewer', 'Charlie')
+
+console.log(admin.permissions) // ['read', 'write', 'delete', 'manage-users']
+console.log(editor.permissions) // ['read', 'write']
+console.log(viewer.greet()) // "Hi, I'm Charlie"
+```
+
+### When to Use the Factory Pattern
+
+- **Creating objects with complex setup** — Encapsulate the complexity
+- **Creating different types based on input** — Switch logic in one place
+- **Decoupling creation from usage** — Callers don't need to know implementation details
+
+
+**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.
+
+
+
+
+ Complete guide to the Factory Method pattern with diagrams and examples
+
+
+
+---
+
+## The Observer Pattern
+
+The **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."
+
+This pattern is everywhere: DOM events, React state updates, Redux subscriptions, Node.js EventEmitter, and RxJS observables all use variations of Observer.
+
+### Building an Observable
+
+```javascript
+class Observable {
+ constructor() {
+ this.observers = []
+ }
+
+ subscribe(fn) {
+ this.observers.push(fn)
+ // Return an unsubscribe function
+ return () => {
+ this.observers = this.observers.filter(observer => observer !== fn)
+ }
+ }
+
+ notify(data) {
+ this.observers.forEach(observer => observer(data))
+ }
+}
+
+// Usage: A stock price tracker
+const stockPrice = new Observable()
+
+// Subscriber 1: Log to console
+const unsubscribeLogger = stockPrice.subscribe(price => {
+ console.log(`Stock price updated: $${price}`)
+})
+
+// Subscriber 2: Check for alerts
+stockPrice.subscribe(price => {
+ if (price > 150) {
+ console.log('ALERT: Price above $150!')
+ }
+})
+
+// Subscriber 3: Update UI (simulated)
+stockPrice.subscribe(price => {
+ console.log(`Updating chart with price: $${price}`)
+})
+
+// When price changes, all subscribers are notified
+stockPrice.notify(145)
+// "Stock price updated: $145"
+// "Updating chart with price: $145"
+
+stockPrice.notify(155)
+// "Stock price updated: $155"
+// "ALERT: Price above $150!"
+// "Updating chart with price: $155"
+
+// Unsubscribe the logger
+unsubscribeLogger()
+
+stockPrice.notify(160)
+// No log message, but alert and chart still update
+```
+
+### The Magazine Subscription Analogy
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ THE OBSERVER PATTERN │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ PUBLISHER (Observable) SUBSCRIBERS (Observers) │
+│ ────────────────────── ─────────────────────── │
+│ │
+│ ┌─────────────────────┐ ┌─────────────┐ │
+│ │ │ ──────────► │ Reader #1 │ │
+│ │ Magazine │ └─────────────┘ │
+│ │ Publisher │ ┌─────────────┐ │
+│ │ │ ──────────► │ Reader #2 │ │
+│ │ • subscribers[] │ └─────────────┘ │
+│ │ • subscribe() │ ┌─────────────┐ │
+│ │ • unsubscribe() │ ──────────► │ Reader #3 │ │
+│ │ • notify() │ └─────────────┘ │
+│ │ │ │
+│ └─────────────────────┘ │
+│ │
+│ When a new issue publishes, all subscribers receive it automatically. │
+│ Readers can subscribe or unsubscribe at any time. │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+### Real-World Example: Form Validation
+
+```javascript
+// Observable form field
+class FormField {
+ constructor(initialValue = '') {
+ this.value = initialValue
+ this.observers = []
+ }
+
+ subscribe(fn) {
+ this.observers.push(fn)
+ return () => {
+ this.observers = this.observers.filter(o => o !== fn)
+ }
+ }
+
+ setValue(newValue) {
+ this.value = newValue
+ this.observers.forEach(fn => fn(newValue))
+ }
+}
+
+// Usage
+const emailField = new FormField('')
+
+// Validator subscriber
+emailField.subscribe(value => {
+ const isValid = value.includes('@')
+ console.log(isValid ? 'Valid email' : 'Invalid email')
+})
+
+// Character counter subscriber
+emailField.subscribe(value => {
+ console.log(`Characters: ${value.length}`)
+})
+
+emailField.setValue('test')
+// "Invalid email"
+// "Characters: 4"
+
+emailField.setValue('test@example.com')
+// "Valid email"
+// "Characters: 16"
+```
+
+
+
+ Complete explanation with UML diagrams and pseudocode
+
+
+
+---
+
+## The Proxy Pattern
+
+The **[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.
+
+### Basic Proxy Example
+
+```javascript
+const user = {
+ name: 'Alice',
+ age: 25,
+ email: 'alice@example.com'
+}
+
+const userProxy = new Proxy(user, {
+ // Intercept property reads
+ get(target, property) {
+ console.log(`Accessing property: ${property}`)
+ return target[property]
+ },
+
+ // Intercept property writes
+ set(target, property, value) {
+ console.log(`Setting ${property} to ${value}`)
+
+ // Validation: age must be a non-negative number
+ if (property === 'age') {
+ if (typeof value !== 'number' || value < 0) {
+ throw new Error('Age must be a non-negative number')
+ }
+ }
+
+ // Validation: email must contain @
+ if (property === 'email') {
+ if (!value.includes('@')) {
+ throw new Error('Invalid email format')
+ }
+ }
+
+ target[property] = value
+ return true
+ }
+})
+
+// All access goes through the proxy
+console.log(userProxy.name)
+// "Accessing property: name"
+// "Alice"
+
+userProxy.age = 26
+// "Setting age to 26"
+
+userProxy.age = -5
+// Error: Age must be a non-negative number
+
+userProxy.email = 'invalid'
+// Error: Invalid email format
+```
+
+### Practical Use Case: Lazy Loading
+
+```javascript
+// Expensive object that we don't want to create until needed
+function createExpensiveResource() {
+ console.log('Creating expensive resource...')
+ return {
+ data: 'Loaded data from database',
+ process() {
+ return `Processing: ${this.data}`
+ }
+ }
+}
+
+// Proxy that delays creation until first use
+function createLazyResource() {
+ let resource = null
+
+ return new Proxy({}, {
+ get(target, property) {
+ // Create resource on first access
+ if (!resource) {
+ resource = createExpensiveResource()
+ }
+
+ const value = resource[property]
+ // If it's a method, bind it to the resource
+ return typeof value === 'function' ? value.bind(resource) : value
+ }
+ })
+}
+
+const lazyResource = createLazyResource()
+console.log('Proxy created, resource not loaded yet')
+
+// Resource is only created when we actually use it
+console.log(lazyResource.data)
+// "Creating expensive resource..."
+// "Loaded data from database"
+
+console.log(lazyResource.process())
+// "Processing: Loaded data from database"
+```
+
+### When to Use the Proxy Pattern
+
+| Use Case | Example |
+|----------|---------|
+| **Validation** | Validate data before setting properties |
+| **Logging/Debugging** | Log all property accesses for debugging |
+| **Lazy initialization** | Delay expensive object creation |
+| **Access control** | Restrict access to certain properties |
+| **Caching** | Cache expensive computations |
+
+
+
+ Complete API reference for JavaScript's Proxy object
+
+
+ Pattern explanation with diagrams and use cases
+
+
+
+---
+
+## The Decorator Pattern
+
+The **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."
+
+In JavaScript, decorators are often implemented as functions that take an object and return an enhanced version.
+
+### Adding Abilities to Objects
+
+```javascript
+// Base object
+const createCharacter = (name) => ({
+ name,
+ health: 100,
+ describe() {
+ return `${this.name} (${this.health} HP)`
+ }
+})
+
+// Decorator: Add flying ability
+const withFlying = (character) => ({
+ ...character,
+ fly() {
+ return `${character.name} soars through the sky!`
+ },
+ describe() {
+ return `${character.describe()} [Can fly]`
+ }
+})
+
+// Decorator: Add swimming ability
+const withSwimming = (character) => ({
+ ...character,
+ swim() {
+ return `${character.name} dives into the water!`
+ },
+ describe() {
+ return `${character.describe()} [Can swim]`
+ }
+})
+
+// Decorator: Add armor
+const withArmor = (character, armorPoints) => ({
+ ...character,
+ armor: armorPoints,
+ takeDamage(amount) {
+ const reducedDamage = Math.max(0, amount - armorPoints)
+ character.health -= reducedDamage
+ return `${character.name} takes ${reducedDamage} damage (${armorPoints} blocked)`
+ },
+ describe() {
+ return `${character.describe()} [Armor: ${armorPoints}]`
+ }
+})
+
+// Compose decorators to build characters
+const duck = withSwimming(withFlying(createCharacter('Duck')))
+console.log(duck.describe()) // "Duck (100 HP) [Can fly] [Can swim]"
+console.log(duck.fly()) // "Duck soars through the sky!"
+console.log(duck.swim()) // "Duck dives into the water!"
+
+const knight = withArmor(createCharacter('Knight'), 20)
+console.log(knight.describe()) // "Knight (100 HP) [Armor: 20]"
+console.log(knight.takeDamage(50)) // "Knight takes 30 damage (20 blocked)"
+```
+
+### Function Decorators
+
+Decorators also work great with functions:
+
+```javascript
+// Decorator: Log function calls
+const withLogging = (fn, fnName) => {
+ return function(...args) {
+ console.log(`Calling ${fnName} with:`, args)
+ const result = fn.apply(this, args)
+ console.log(`${fnName} returned:`, result)
+ return result
+ }
+}
+
+// Decorator: Memoize (cache) results
+const withMemoization = (fn) => {
+ const cache = new Map()
+
+ return function(...args) {
+ const key = JSON.stringify(args)
+
+ if (cache.has(key)) {
+ console.log('Cache hit!')
+ return cache.get(key)
+ }
+
+ const result = fn.apply(this, args)
+ cache.set(key, result)
+ return result
+ }
+}
+
+// Original function
+function fibonacci(n) {
+ if (n <= 1) return n
+ return fibonacci(n - 1) + fibonacci(n - 2)
+}
+
+// Decorated version with logging
+const loggedAdd = withLogging((a, b) => a + b, 'add')
+loggedAdd(2, 3)
+// "Calling add with: [2, 3]"
+// "add returned: 5"
+
+// Decorated fibonacci with memoization
+const memoizedFib = withMemoization(function fib(n) {
+ if (n <= 1) return n
+ return memoizedFib(n - 1) + memoizedFib(n - 2)
+})
+
+console.log(memoizedFib(10)) // 55
+console.log(memoizedFib(10)) // "Cache hit!" — 55
+```
+
+### When to Use the Decorator Pattern
+
+- **Adding features without modifying original code** — Open/Closed Principle
+- **Composing behaviors dynamically** — Mix and match capabilities
+- **Cross-cutting concerns** — Logging, caching, validation, timing
+
+
+
+ Full explanation with structure diagrams and applicability guidelines
+
+
+
+---
+
+## Common Mistakes with Design Patterns
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ DESIGN PATTERN MISTAKES │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ MISTAKE #1: PATTERN OVERUSE │
+│ ─────────────────────────── │
+│ Using patterns where simple code would work better. │
+│ A plain function is often better than a Factory class. │
+│ │
+│ MISTAKE #2: WRONG PATTERN CHOICE │
+│ ───────────────────────────── │
+│ Using Singleton when you just need a module export. │
+│ Using Observer when a simple callback would suffice. │
+│ │
+│ MISTAKE #3: IGNORING JAVASCRIPT IDIOMS │
+│ ──────────────────────────────────── │
+│ JavaScript has closures, first-class functions, and ES modules. │
+│ Many classical patterns simplify dramatically in JavaScript. │
+│ │
+│ MISTAKE #4: PREMATURE ABSTRACTION │
+│ ──────────────────────────────── │
+│ Adding patterns before you have a real problem to solve. │
+│ "You Ain't Gonna Need It" (YAGNI) applies to patterns too. │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+### The "Golden Hammer" Anti-Pattern
+
+When you learn a new pattern, resist the urge to use it everywhere:
+
+```javascript
+// ❌ OVERKILL: Factory for simple objects
+class UserFactory {
+ createUser(name) {
+ return new User(name)
+ }
+}
+const factory = new UserFactory()
+const user = factory.createUser('Alice')
+
+// ✓ SIMPLE: Just create the object
+const user = { name: 'Alice' }
+// or
+const user = new User('Alice')
+```
+
+
+**Ask yourself these questions before using a pattern:**
+
+1. **Do I have a real problem?** Don't solve problems you don't have yet.
+2. **Is there a simpler solution?** A plain function or object might be enough.
+3. **Does JavaScript already solve this?** ES modules, Promises, and iterators are built-in patterns.
+4. **Will my team understand it?** Patterns only help if everyone knows them.
+
+
+---
+
+## Choosing the Right Pattern
+
+| Problem | Pattern | Alternative |
+|---------|---------|-------------|
+| Need to organize code with private state | **Module** | ES6 module exports |
+| Need exactly one instance | **Singleton** | Just export an object from a module |
+| Need to create objects dynamically | **Factory** | Plain function returning objects |
+| Need to notify multiple listeners of changes | **Observer** | EventEmitter, callbacks, or a library |
+| Need to control or validate object access | **Proxy** | Getter/setter methods |
+| Need to add behavior without modification | **Decorator** | Higher-order functions, composition |
+
+
+**Rule of Thumb:** Start with the simplest solution that works. Introduce patterns when you hit a real problem they solve, not before.
+
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **Design patterns are templates, not code** — Adapt them to your specific problem; don't force-fit them
+
+2. **JavaScript simplifies many patterns** — First-class functions, closures, and ES modules reduce boilerplate
+
+3. **Module pattern organizes code** — Use ES modules for new projects; understand IIFE pattern for legacy code
+
+4. **Singleton is often unnecessary** — ES module exports are already cached; use sparingly if at all
+
+5. **Factory centralizes object creation** — Great for creating different types based on input
+
+6. **Observer enables event-driven code** — The foundation of DOM events, React state, and reactive programming
+
+7. **Proxy intercepts object operations** — Use for validation, logging, lazy loading, and access control
+
+8. **Decorator adds behavior through wrapping** — Compose features without modifying original code
+
+9. **Avoid pattern overuse** — Simple code beats clever patterns; apply the YAGNI principle
+
+10. **Learn to recognize patterns in the wild** — DOM events use Observer, Promises use a form of Observer, middleware uses Decorator
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ The Module pattern encapsulates code into reusable units with **private and public parts**. It allows you to:
+ - Hide implementation details (private variables and functions)
+ - Expose only a public API
+ - Avoid polluting the global namespace
+
+ In modern JavaScript, ES6 modules (`import`/`export`) provide this naturally. Variables in a module are private unless exported.
+
+ ```javascript
+ // privateHelper is not exported — it's private
+ function privateHelper() { /* ... */ }
+
+ // Only publicFunction is accessible to importers
+ export function publicFunction() {
+ privateHelper()
+ }
+ ```
+
+
+
+ **Answer:**
+
+ Singleton is often unnecessary in JavaScript because:
+
+ 1. **ES modules are already singletons** — When you export an object, all importers get the same instance
+ 2. **Testing difficulties** — Tests share state, making isolation hard
+ 3. **Hidden dependencies** — Code using Singletons has implicit dependencies
+ 4. **JavaScript can create objects directly** — No need for the class-based workarounds other languages require
+
+ ```javascript
+ // ES module — already a singleton!
+ export const config = { apiUrl: '...' }
+
+ // Every import gets the same object
+ import { config } from './config.js' // Same instance everywhere
+ ```
+
+
+
+ **Answer:**
+
+ The Observer pattern has three key parts:
+
+ 1. **Subscriber list** — An array to store observer functions
+ 2. **Subscribe method** — Adds a function to the list (often returns an unsubscribe function)
+ 3. **Notify method** — Calls all subscribed functions with data
+
+ ```javascript
+ class Observable {
+ constructor() {
+ this.observers = [] // 1. Subscriber list
+ }
+
+ subscribe(fn) { // 2. Subscribe method
+ this.observers.push(fn)
+ return () => { // Returns unsubscribe
+ this.observers = this.observers.filter(o => o !== fn)
+ }
+ }
+
+ notify(data) { // 3. Notify method
+ this.observers.forEach(fn => fn(data))
+ }
+ }
+ ```
+
+
+
+ **Answer:**
+
+ Both wrap objects, but they have different purposes:
+
+ **Proxy Pattern:**
+ - **Controls access** to an object
+ - Intercepts operations like get, set, delete
+ - The proxy typically has the same interface as the target
+ - Use for: validation, logging, lazy loading, access control
+
+ **Decorator Pattern:**
+ - **Adds new behavior** to an object
+ - Wraps the object and extends its capabilities
+ - May add new methods or modify existing ones
+ - Use for: composing features, cross-cutting concerns
+
+ ```javascript
+ // Proxy — same interface, controlled access
+ const proxy = new Proxy(obj, { get(t, p) { /* intercept */ } })
+
+ // Decorator — enhanced interface, new behavior
+ const enhanced = withLogging(withCache(obj))
+ ```
+
+
+
+ **Answer:**
+
+ Use the Factory pattern when:
+
+ 1. **Object creation is complex** — Encapsulate setup logic in one place
+ 2. **You need different types based on input** — Switch logic centralized in the factory
+ 3. **You want to decouple creation from usage** — Callers don't need to know implementation
+ 4. **You might change how objects are created** — Update the factory, not every call site
+
+ ```javascript
+ // Factory — creation logic in one place
+ function createNotification(type, message) {
+ switch (type) {
+ case 'error': return { type, message, color: 'red' }
+ case 'success': return { type, message, color: 'green' }
+ default: return { type: 'info', message, color: 'blue' }
+ }
+ }
+
+ // Easy to use — no need to know the structure
+ const notification = createNotification('error', 'Something went wrong')
+ ```
+
+
+
+ **Answer:**
+
+ The "Golden Hammer" anti-pattern is the tendency to use a familiar tool (or pattern) for every problem, even when it's not appropriate.
+
+ **Signs you're doing this:**
+ - Using Singleton for everything that "should be global"
+ - Creating Factory classes for simple object literals
+ - Using Observer when a callback would suffice
+ - Adding patterns before you have a real problem
+
+ **How to avoid it:**
+ - Start with the simplest solution
+ - Add patterns only when you hit a real problem they solve
+ - Ask: "Would a plain function/object work here?"
+ - Remember: Code clarity beats clever patterns
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Deep dive into object creation with factory functions and ES6 classes
+
+
+ How JavaScript evolved from IIFEs to modern ES modules
+
+
+ Functions that work with functions — the foundation of many patterns
+
+
+ How closures enable private state in the Module pattern
+
+
+
+---
+
+## Reference
+
+
+
+ Complete API reference for JavaScript's built-in Proxy object
+
+
+ Official guide to ES6 modules with import and export
+
+
+ Complete catalog of classic design patterns with examples
+
+
+ The Reflect object used with Proxy for default behavior
+
+
+
+## Articles
+
+
+
+ Lydia Hallie and Addy Osmani's modern guide with animated visualizations. Each pattern gets its own interactive explanation showing exactly how data flows.
+
+
+ Beginner-friendly walkthrough of essential patterns with practical code examples. Great starting point if you're new to design patterns.
+
+
+ Addy Osmani's free online book, updated for modern JavaScript. The definitive resource covering patterns, anti-patterns, and real-world applications.
+
+
+ Authoritative guide on adding behaviors to classes without inheritance. Shows the EventMixin pattern that's used throughout JavaScript libraries.
+
+
+
+## Videos
+
+
+
+ Fireship's fast-paced overview covering the essential patterns every developer should know. Perfect for a quick refresher or introduction.
+
+
+ Free comprehensive course covering MVC, MVP, and organizing large JavaScript applications. Great for understanding patterns in context.
+
+
+ Fun Fun Function's engaging explanation of factories vs classes. MPJ's conversational style makes complex concepts approachable.
+
+
diff --git a/docs/concepts/dom.mdx b/docs/concepts/dom.mdx
new file mode 100644
index 00000000..83fe1a5f
--- /dev/null
+++ b/docs/concepts/dom.mdx
@@ -0,0 +1,2157 @@
+---
+title: "DOM: How Browsers Represent Web Pages in JavaScript"
+sidebarTitle: "DOM: How Browsers Represent Web Pages"
+description: "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."
+---
+
+How 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?
+
+```javascript
+// The DOM lets you do things like this:
+document.querySelector('h1').textContent = 'Hello, DOM!'
+document.body.style.backgroundColor = 'lightblue'
+document.getElementById('btn').addEventListener('click', handleClick)
+```
+
+The **[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.
+
+
+**What you'll learn in this guide:**
+- What the DOM is in JavaScript and how it differs from HTML
+- How to select DOM elements (getElementById vs querySelector)
+- How to traverse the DOM tree (parent, children, siblings)
+- How to manipulate DOM elements (create, modify, remove)
+- The difference between properties and attributes
+- How the browser turns DOM → pixels (the Critical Rendering Path)
+- Performance best practices (avoid layout thrashing!)
+
+
+
+**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!
+
+
+---
+
+## What is the DOM in JavaScript?
+
+The **[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. 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.**
+
+---
+
+## How the DOM Tree Structure Works
+
+Think of the DOM like a family tree. At the top sits `document` (the family historian who knows everyone). Below it is `` (the matriarch), which has two children: `` and ``. Each of these has their own children, grandchildren, and so on.
+
+```
+ THE DOM FAMILY TREE
+
+ ┌──────────┐
+ │ document │ ← The family historian
+ │ (root) │ (knows everyone!)
+ └────┬─────┘
+ │
+ ┌────┴─────┐
+ │ │ ← Great-grandma
+ └────┬─────┘ (the matriarch)
+ ┌─────────────┴─────────────┐
+ │ │
+ ┌────┴────┐ ┌────┴────┐
+ │ │ │ │ ← The two branches
+ └────┬────┘ └────┬────┘ of the family
+ │ │
+ ┌──────┴──────┐ ┌──────────┼──────────┐
+ │ │ │ │ │
+ ┌────┴────┐ ┌────┴────┐ ┌───┴───┐ ┌────┴────┐ ┌───┴───┐
+ │ │ │ │ │