> ## Documentation Index
> Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript Crash Course

> Master the language of the web and beyond

# JavaScript Crash Course

> **JavaScript** is the most ubiquitous programming language in the world. It runs in every browser, powers servers with Node.js, builds mobile apps, and even trains machine learning models. If you learn one language, make it JavaScript.

This crash course is designed to take you from "Hello World" to understanding closures, prototypes, async/await, and modern ES6+ features.

***

## Why JavaScript?

JavaScript has evolved from a simple scripting language to a versatile powerhouse.

<CardGroup cols={2}>
  <Card title="Runs Everywhere" icon="globe">
    From browsers to servers (Node.js) to mobile (React Native) to desktop (Electron) — JavaScript is truly universal.
  </Card>

  <Card title="Massive Ecosystem" icon="cubes">
    npm is the world's largest package registry with over 2 million packages. There's a library for everything.
  </Card>

  <Card title="Async by Nature" icon="bolt">
    Built-in event loop and async primitives make handling I/O, network calls, and user interactions seamless.
  </Card>

  <Card title="Rapid Evolution" icon="rocket">
    With yearly ECMAScript updates, JavaScript keeps getting better: async/await, modules, optional chaining, and more.
  </Card>
</CardGroup>

## Course Roadmap

We will peel back the layers of abstraction to understand how JavaScript really works.

<Steps>
  <Step title="Fundamentals">
    Understand variables, types, operators, and control flow.
    [Start Learning](/courses/javascript-crash-course/fundamentals)
  </Step>

  <Step title="Functions & Scope">
    First-class functions, closures, and the execution context.
    [Explore Functions](/courses/javascript-crash-course/functions-scope)
  </Step>

  <Step title="Objects & Prototypes">
    Objects, prototypal inheritance, and the `this` keyword.
    [Master Objects](/courses/javascript-crash-course/objects-prototypes)
  </Step>

  <Step title="Async JavaScript">
    Callbacks, Promises, async/await, and the Event Loop.
    [Go Async](/courses/javascript-crash-course/async)
  </Step>

  <Step title="Modern JavaScript (ES6+)">
    Destructuring, modules, classes, and the latest features.
    [Go Modern](/courses/javascript-crash-course/modern-js)
  </Step>

  <Step title="DOM & Browser APIs">
    Manipulating the DOM, handling events, and browser APIs.
    [Build for the Web](/courses/javascript-crash-course/dom-browser)
  </Step>
</Steps>

## Quick Reference -- JavaScript's Most Common Gotchas

If you read nothing else before starting, know these. Each is covered in depth in the relevant chapter.

| Gotcha                    | What happens                                          | Fix                                       |
| :------------------------ | :---------------------------------------------------- | :---------------------------------------- |
| `typeof null`             | Returns `'object'` (25-year-old bug)                  | Use `value === null` to check for null    |
| `0.1 + 0.2`               | `0.30000000000000004` (IEEE 754 floats)               | Use integer math for money (cents)        |
| `'5' + 3`                 | `'53'` (string concatenation, not addition)           | Use `Number('5') + 3` or `+'5' + 3`       |
| `[] == false`             | `true` (coercion through `""` to `0`)                 | Always use `===` (strict equality)        |
| `var` in loops            | Shared across iterations (closure bug)                | Use `let` for block-scoped loop variable  |
| `this` in callbacks       | Loses object context                                  | Use arrow functions or `.bind()`          |
| `.sort()` no comparator   | Sorts as strings: `[10, 9, 80]` becomes `[10, 80, 9]` | Always pass `(a, b) => a - b` for numbers |
| `fetch` on 404/500        | Does not throw (only network errors throw)            | Check `response.ok` before reading body   |
| `{ ...obj }` with nesting | Shallow copy (nested objects shared)                  | Use `structuredClone()` for deep copy     |
| `async` function return   | Always returns a Promise, never a raw value           | Use `await` to unwrap                     |

## Prerequisites

* Basic programming knowledge (any language).
* A modern browser (Chrome, Firefox, Edge).
* Node.js installed for running JS outside the browser (`node -v`).
* A code editor (VS Code is highly recommended).

## The JavaScript Philosophy

> "Any application that can be written in JavaScript, will eventually be written in JavaScript." -- Atwood's Law

JavaScript is a **multi-paradigm** language. You can write object-oriented, functional, or procedural code. It's **dynamically typed** (flexibility at the cost of runtime errors), and **single-threaded** with an **event-driven** architecture.

Think of JavaScript like a Swiss Army knife: it is not the best dedicated tool for any single job, but it is the only tool that works in every environment you will encounter on the web. A backend engineer might reach for Go or Rust for raw performance. A data scientist might prefer Python. But JavaScript is the one language that runs natively in every browser on the planet, on every server via Node.js, and increasingly on edge runtimes and IoT devices. That universality is its superpower -- and the reason it is worth learning deeply, quirks and all.

<Warning>
  **Heads up before you dive in.** JavaScript has a few infamous quirks that trip up every newcomer: automatic type coercion (`'5' + 3` gives you `'53'`, not `8`), the `this` keyword changing meaning depending on how you call a function, and variable hoisting with `var`. This course tackles each of these head-on. Do not let them scare you -- once you understand *why* they exist, they become predictable.
</Warning>

```javascript theme={null}
// A taste of JavaScript -- functional-style data processing in three lines
const greet = (name) => `Hello, ${name}!`;

const names = ['Alice', 'Bob', 'Charlie'];

names
  .filter(name => name.startsWith('A'))  // Keep only names starting with 'A'
  .map(greet)                            // Transform each name into a greeting
  .forEach(console.log);                 // Print each greeting

// Output: "Hello, Alice!"
```

***

## Interview Deep-Dive

<AccordionGroup>
  <Accordion title="JavaScript is single-threaded. How does it handle thousands of concurrent connections in Node.js without blocking?">
    **Strong Answer:**

    * The key insight is that single-threaded does not mean single-tasked. JavaScript uses a single call stack for executing code, but it offloads I/O operations (file reads, network requests, database queries) to the operating system's kernel or a thread pool managed by libuv (in Node.js) or the browser's Web APIs.
    * When an async operation like `fs.readFile` is called, Node hands it off to the OS or a worker thread. The main thread is immediately free to process the next event. When the I/O completes, a callback is placed on the event loop's task queue. The event loop picks it up only when the call stack is empty.
    * This is why Node.js excels at I/O-bound workloads (API servers, real-time apps) but struggles with CPU-bound tasks (image processing, heavy computation). A CPU-bound task blocks the single thread and starves every other request. The mitigation is `worker_threads` in Node.js or Web Workers in the browser, which spin up actual OS threads for computation.
    * In production, a Node.js server handling 10,000 concurrent WebSocket connections is not running 10,000 threads. It is running one thread that rapidly cycles through event callbacks. The bottleneck is never the concurrency model -- it is what you do on the main thread between events.

    **Follow-up: If a single CPU-bound task can block everything, how would you architect a Node.js service that needs to resize uploaded images while also serving API requests?**

    You would never do image resizing on the main event loop thread. The standard approaches are:

    * Use `worker_threads` to offload the resize to a separate thread. The main thread posts the image buffer to the worker and gets a message back when it is done. This keeps the event loop free.
    * Use a separate microservice or job queue (like Bull/BullMQ backed by Redis) where the API server enqueues a resize job and a dedicated worker process picks it up. This is the production-standard pattern at scale because it lets you scale API servers and image workers independently.
    * Use a native addon like `sharp` (which calls into libvips via C++ bindings and releases the GIL equivalent automatically), so the heavy lifting happens off the main thread even without explicit worker usage.
    * The anti-pattern is calling a synchronous image processing library directly in an Express route handler. I have seen this take down a production API serving 500 requests per second because a single 5MB image resize blocked the event loop for 800ms, causing every other request to queue up behind it.
  </Accordion>

  <Accordion title="Explain type coercion in JavaScript. Why does [] == ![] evaluate to true?">
    **Strong Answer:**

    * JavaScript's `==` operator triggers the Abstract Equality Comparison algorithm (defined in the ECMAScript spec, section 7.2.14), which performs type coercion before comparison. The `===` operator skips coercion entirely and compares type + value.
    * For `[] == ![]`: first, `![]` is evaluated. Since `[]` is truthy (all objects are truthy), `![]` becomes `false`. Now we have `[] == false`. The spec says: if one side is boolean, convert it to a number. `false` becomes `0`. Now we have `[] == 0`. The spec says: if one side is an object and the other is a number, call `ToPrimitive` on the object. `[].valueOf()` returns the array itself (not a primitive), so it falls through to `[].toString()`, which returns `""`. Now we have `"" == 0`. The spec says: if one side is a string and the other is a number, convert the string to a number. `Number("")` is `0`. Now we have `0 == 0`, which is `true`.
    * The practical lesson is not to memorize every coercion path, but to internalize one rule: always use `===` unless you have a specific, documented reason to use `==`. The one defensible exception is `value == null`, which catches both `null` and `undefined` in a single comparison.
    * In production, linting rules like ESLint's `eqeqeq` enforce this automatically. At a previous team I worked on, we had a bug where a form field value of `"0"` was being treated as falsy in an `if (value)` check, causing a valid zero input to be silently discarded. The fix was switching to `if (value !== null && value !== undefined)` -- or using the nullish coalescing operator.

    **Follow-up: What is the difference between `Object.is()` and `===`, and when does it matter?**

    `Object.is()` differs from `===` in exactly two cases: `Object.is(NaN, NaN)` returns `true` (whereas `NaN === NaN` is `false`), and `Object.is(-0, 0)` returns `false` (whereas `-0 === 0` is `true`). This matters in specific scenarios: if you are implementing a memoization cache and a function is called with `NaN` as an argument, `===` would fail to detect a cache hit. React uses `Object.is` internally for its dependency comparison in `useEffect` and `useMemo` hooks -- this is why passing `NaN` as a dependency does not cause infinite re-renders.
  </Accordion>

  <Accordion title="JavaScript is called multi-paradigm. What does that mean concretely, and how does it affect architectural decisions on a real project?">
    **Strong Answer:**

    * Multi-paradigm means JavaScript supports object-oriented programming (prototypal inheritance, classes), functional programming (first-class functions, closures, immutability patterns), and procedural/imperative programming (sequential statements, loops). You are not locked into one style the way you are with, say, Haskell (functional) or Java pre-8 (OOP).
    * Concretely, this affects architecture because different parts of a codebase may benefit from different paradigms. Data transformation pipelines (parsing API responses, transforming state) are often cleanest as functional chains: `data.filter(...).map(...).reduce(...)`. State management and encapsulation (a database connection pool, a cache with TTL) often benefit from OOP with classes. Glue code and scripts are often simplest as imperative procedures.
    * The risk is inconsistency. On a team of 8 engineers, if half write functional-style code and half write class-based OOP, the codebase becomes incoherent. The practical solution is to establish conventions: "We use functional style for data transforms, classes for services, and we never mix paradigms within a single module." Linting rules and code review enforce this.
    * A real-world example: in a React + Node.js codebase, the frontend is typically functional (function components, hooks, pure render functions) while the backend services might be class-based (NestJS controllers, injectable services). Trying to force one paradigm everywhere leads to awkward code -- a React component written as a class in 2026 feels archaic, and a complex stateful service written as nested closures feels unreadable.

    **Follow-up: When would you explicitly choose a functional approach over OOP in JavaScript, and what are the trade-offs?**

    I would choose functional when the domain is about transformations: mapping API responses, building UI from state, data validation pipelines. The benefits are testability (pure functions with no side effects are trivial to unit test), composability (pipe/compose small functions into larger ones), and predictability (no hidden state mutations). The trade-offs are: deeply nested closures can be harder to debug (stack traces are less readable), performance can suffer if you create many intermediate arrays in hot paths, and some domains (stateful connections, resource lifecycle management) are genuinely more natural to express as objects with methods. The pragmatic answer is: use both, but within clear boundaries.
  </Accordion>
</AccordionGroup>
