> ## 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.

# Functions & Scope

> First-class Functions, Closures, and the Execution Context

# Functions & Scope

Functions are **first-class citizens** in JavaScript. They can be assigned to variables, passed as arguments, and returned from other functions. This makes JavaScript incredibly flexible and powerful.

"First-class citizen" means functions are treated like any other value. You can store a function in a variable the same way you store a number. You can pass a function into another function as an argument, the way you pass a string. You can return a function from a function, like returning a configured tool from a factory. This is the single most important idea in JavaScript -- it unlocks closures, callbacks, higher-order functions, and most of the patterns you will use every day.

***

## 1. Function Declarations vs Expressions

### Function Declaration (Hoisted)

```javascript theme={null}
// Can be called before it's defined -- this is "hoisting" in action.
// JavaScript reads all function declarations during the compilation phase,
// BEFORE it runs any code. So the function exists from the very first line.
greet('Alice'); // Works!

function greet(name) {
    return `Hello, ${name}!`;
}
```

### Function Expression (Not Hoisted)

```javascript theme={null}
// Cannot be called before assignment.
// The variable 'greet' is hoisted, but its VALUE (the function) is not assigned
// until this line executes. Before that, greet is undefined (let/const) or
// would throw a ReferenceError.
greet('Alice'); // ReferenceError: Cannot access 'greet' before initialization

const greet = function(name) {
    return `Hello, ${name}!`;
};
```

### Arrow Functions (ES6)

Concise syntax, and they don't have their own `this`.

```javascript theme={null}
// Basic syntax -- implicit return for single expressions
const add = (a, b) => a + b;

// With body block -- explicit return required when using curly braces
const greet = (name) => {
    const message = `Hello, ${name}!`;
    return message; // Without this return, the function returns undefined!
};

// Single parameter -- parentheses optional (but many style guides require them)
const double = x => x * 2;

// No parameters -- parentheses required
const sayHi = () => 'Hi!';

// GOTCHA: Returning an object literal requires wrapping in parentheses
const makeUser = (name) => ({ name, role: 'user' });
// Without parens: const makeUser = (name) => { name, role: 'user' };
// JavaScript thinks the curly braces are a function body, not an object!
```

<Tip>
  **When to use arrow functions?** Use them for short, anonymous functions (callbacks, `map`/`filter`). Use regular functions when you need your own `this` binding (object methods), when you need `arguments` object access, or when you need hoisting. Arrow functions do not have their own `this`, `arguments`, or `super`.
</Tip>

### Function Types -- Complete Comparison

| Feature                          | Declaration              | Expression                    | Arrow                              |
| :------------------------------- | :----------------------- | :---------------------------- | :--------------------------------- |
| Syntax                           | `function name() {}`     | `const name = function() {}`  | `const name = () => {}`            |
| Hoisted                          | Yes (entire function)    | No (only variable, not value) | No (only variable, not value)      |
| Has own `this`                   | Yes                      | Yes                           | No (inherits from enclosing scope) |
| Has `arguments`                  | Yes                      | Yes                           | No (use rest params `...args`)     |
| Can be a constructor (`new`)     | Yes                      | Yes                           | No (`TypeError`)                   |
| Has `prototype` property         | Yes                      | Yes                           | No                                 |
| Implicit return                  | No                       | No                            | Yes (single expression only)       |
| Can be a generator (`function*`) | Yes                      | Yes                           | No                                 |
| Best used for                    | Named functions, methods | Callbacks, IIFEs              | Short callbacks, preserving `this` |

**Decision guide -- which function syntax to use:**

* **Object/class methods**: Use method shorthand (`greet() {}`) or regular functions. They need their own `this`.
* **Callbacks for `.map`, `.filter`, `.then`**: Use arrow functions. Concise and no `this` confusion.
* **Event handlers in classes**: Use arrow functions or `.bind()` to preserve `this`.
* **Top-level named functions**: Use declarations. Hoisting makes them available throughout the file.
* **IIFEs**: Either works, but arrow IIFEs (`(() => { ... })()`) are more common in modern code.

***

## 2. Parameters & Arguments

### Default Parameters (ES6)

```javascript theme={null}
function greet(name = 'Guest') {
    return `Hello, ${name}!`;
}

greet();        // 'Hello, Guest!'
greet('Alice'); // 'Hello, Alice!'
```

### Rest Parameters

Collect remaining arguments into an array.

```javascript theme={null}
function sum(...numbers) {
    return numbers.reduce((total, n) => total + n, 0);
}

sum(1, 2, 3, 4); // 10
```

### Spread Operator

Expand an array into individual arguments.

```javascript theme={null}
const nums = [1, 2, 3];
console.log(Math.max(...nums)); // 3
```

### Rest vs Spread -- They Look Identical But Do Opposite Things

| Syntax                     | Name   | Position             | What it does                               |
| :------------------------- | :----- | :------------------- | :----------------------------------------- |
| `function fn(...args)`     | Rest   | Function parameter   | Collects multiple arguments into one array |
| `fn(...array)`             | Spread | Function call        | Expands one array into multiple arguments  |
| `const [a, ...rest] = arr` | Rest   | Destructuring        | Collects remaining elements into an array  |
| `const copy = [...arr]`    | Spread | Array/Object literal | Expands elements into a new array/object   |

```javascript theme={null}
// Edge case: default parameters are evaluated left-to-right
// Earlier parameters can be used as defaults for later ones
function createRange(start, end = start + 10) {
    return { start, end };
}
createRange(5);    // { start: 5, end: 15 }

// Edge case: passing undefined triggers the default, but null does NOT
function greet(name = 'Guest') {
    return `Hello, ${name}`;
}
greet(undefined);  // 'Hello, Guest' -- undefined triggers default
greet(null);       // 'Hello, null' -- null is a value, not "missing"

// Edge case: arguments object vs rest parameters
function oldStyle() {
    console.log(arguments);        // { '0': 1, '1': 2, '2': 3 } -- array-LIKE, not an array
    console.log(arguments.map);    // undefined -- no array methods!
    console.log([...arguments]);   // [1, 2, 3] -- convert to real array
}
function newStyle(...args) {
    console.log(args);             // [1, 2, 3] -- a real array with all methods
}
```

***

## 3. Scope

Scope determines where variables are accessible. JavaScript has **three types of scope**.

### Global Scope

Variables declared outside any function or block.

```javascript theme={null}
const globalVar = 'I am global';

function test() {
    console.log(globalVar); // Accessible
}
```

### Function Scope

Variables declared inside a function (with `var`, `let`, or `const`).

```javascript theme={null}
function test() {
    var functionScoped = 'Only here';
}
console.log(functionScoped); // ❌ ReferenceError
```

### Block Scope (ES6)

Variables declared with `let` or `const` inside `{}`.

```javascript theme={null}
if (true) {
    let blockScoped = 'Only in this block';
    const alsoBlockScoped = 'Same here';
}
console.log(blockScoped); // ❌ ReferenceError
```

### Lexical Scope (Static Scope)

Functions are executed using the scope in which they were **defined**, not where they are called. Think of it like a postal address: a function's "home address" is fixed at the time it is written. No matter where you call the function from later, it still looks up variables at its home address.

```javascript theme={null}
const name = 'Alice';

function outer() {
    const name = 'Bob';
    
    function inner() {
        // inner() was DEFINED inside outer(), so it looks up 'name'
        // in outer()'s scope first -- not wherever inner() gets called from
        console.log(name); // 'Bob' -- looks up the scope chain
    }
    
    return inner;
}

const fn = outer();
fn(); // 'Bob' -- even though we call fn() in the global scope,
      // it remembers the scope where it was born (lexical environment)
```

***

## 4. Closures

A **closure** is a function that remembers its lexical scope even when executed outside that scope. This is one of the most powerful concepts in JavaScript.

**The backpack analogy**: When a function is created, it packs a "backpack" of all the variables from its surrounding scope. Wherever that function goes -- passed as a callback, returned from another function, stored in a variable -- it carries that backpack with it. Even after the outer function has finished executing and its local variables would normally be garbage collected, the inner function still has access to them through its backpack. That backpack is the closure.

```javascript theme={null}
function createCounter() {
    let count = 0; // This variable goes into the closure's "backpack"
    
    return {
        increment: () => ++count,  // These functions carry 'count' with them
        decrement: () => --count,
        getCount: () => count
    };
}

const counter = createCounter();
// createCounter() has finished executing, but 'count' lives on
// inside the backpack of the returned functions
counter.increment(); // 1
counter.increment(); // 2
counter.getCount();  // 2

// count is not accessible directly -- it is truly private
console.log(counter.count); // undefined
```

### Practical Use Cases

**1. Data Privacy (Module Pattern)**

```javascript theme={null}
const bankAccount = (function() {
    let balance = 0; // Private
    
    return {
        deposit: (amount) => balance += amount,
        withdraw: (amount) => balance -= amount,
        getBalance: () => balance
    };
})();

bankAccount.deposit(100);
bankAccount.getBalance(); // 100
```

**2. Function Factories**

```javascript theme={null}
function multiply(factor) {
    return (number) => number * factor;
}

const double = multiply(2);
const triple = multiply(3);

double(5); // 10
triple(5); // 15
```

**3. Event Handlers with State**

```javascript theme={null}
function createClickHandler(buttonId) {
    let clickCount = 0; // Each handler gets its own private count
    
    return function() {
        clickCount++;
        console.log(`Button ${buttonId} clicked ${clickCount} times`);
    };
}

const handler = createClickHandler('submit');
// Each click remembers the count -- the closure persists clickCount
// between invocations. This is how you maintain state without globals.
```

<Warning>
  **Classic closure gotcha -- loops with `var`**: Before `let` existed, closures in loops were a notorious trap. A `for` loop with `var` creates a single shared variable, so all closures in the loop see the same final value. Using `let` in the loop header fixes this because `let` creates a new binding per iteration.
</Warning>

```javascript theme={null}
// BUG: All timeouts print 3, because var i is shared across iterations
for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100); // 3, 3, 3
}

// FIX: let creates a new 'i' for each loop iteration
for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100); // 0, 1, 2
}
```

***

## 5. The Execution Context and Call Stack

Every time a function is called, JavaScript creates an **Execution Context** -- a box that holds the function's local variables, its `this` value, and a reference to the outer scope. These contexts are managed in a **Call Stack** (Last In, First Out).

Think of the call stack like a stack of plates at a buffet. Every time you call a function, a new plate goes on top. When that function returns, its plate is removed. You can only work with the plate on top. If you keep adding plates without removing any (infinite recursion), the stack crashes.

```javascript theme={null}
function first() {
    console.log('First');
    second();              // Pauses first(), pushes second() onto the stack
    console.log('First again'); // Resumes after second() returns
}

function second() {
    console.log('Second');
    third();               // Pauses second(), pushes third() onto the stack
}

function third() {
    console.log('Third');  // Returns, popped off the stack
}

first();
// Output: First, Second, Third, First again
```

**Call Stack visualization:**

```
1. [Global]
2. [Global] -> [first()]
3. [Global] -> [first()] -> [second()]
4. [Global] -> [first()] -> [second()] -> [third()]
5. [Global] -> [first()] -> [second()] <-- third() returns
6. [Global] -> [first()] <-- second() returns
7. [Global] <-- first() returns
```

<Warning>
  **Stack Overflow**: If you have infinite recursion (a function calling itself without a base case), the call stack overflows and throws `RangeError: Maximum call stack size exceeded`. In Chrome, the default stack size is around 10,000-15,000 frames. You can see the exact call stack in your browser's DevTools when this happens.
</Warning>

***

## 6. Higher-Order Functions

A **higher-order function** either takes a function as an argument or returns a function. They are central to functional programming.

### Functions as Arguments

```javascript theme={null}
const numbers = [1, 2, 3, 4, 5];

// map: Transform each element (returns new array, does NOT mutate original)
const doubled = numbers.map(n => n * 2); // [2, 4, 6, 8, 10]

// filter: Keep elements that pass a test (returns new array)
const evens = numbers.filter(n => n % 2 === 0); // [2, 4]

// reduce: Accumulate to a single value
// The second argument (0) is the initial value for acc. ALWAYS provide it --
// omitting it uses the first array element, which causes bugs on empty arrays.
const sum = numbers.reduce((acc, n) => acc + n, 0); // 15

// find: Get first matching element (returns undefined if not found, not null)
const found = numbers.find(n => n > 3); // 4

// some/every: Boolean tests (short-circuit like && and ||)
numbers.some(n => n > 4);  // true (at least one matches)
numbers.every(n => n > 0); // true (all match)
```

<Tip>
  **Performance note**: `map`, `filter`, and `reduce` each create a new array or value. If you chain three of them, you iterate the array three times. For small arrays this is fine. For arrays with tens of thousands of elements, consider combining operations in a single `reduce`, or using a `for` loop.
</Tip>

### Array Methods -- When to Use Which

| Method              | Returns                      | Mutates Original | Use When                                           |
| :------------------ | :--------------------------- | :--------------- | :------------------------------------------------- |
| `.map(fn)`          | New array (same length)      | No               | Transforming every element                         |
| `.filter(fn)`       | New array (subset)           | No               | Keeping elements that pass a test                  |
| `.reduce(fn, init)` | Single value (any type)      | No               | Accumulating: sums, grouping, building objects     |
| `.find(fn)`         | First match or `undefined`   | No               | Finding one element by condition                   |
| `.findIndex(fn)`    | Index or `-1`                | No               | Finding the position of one element                |
| `.some(fn)`         | `boolean`                    | No               | "Does at least one match?" (short-circuits)        |
| `.every(fn)`        | `boolean`                    | No               | "Do all match?" (short-circuits)                   |
| `.forEach(fn)`      | `undefined`                  | No               | Side effects only (logging, DOM updates)           |
| `.sort(fn)`         | Same array (sorted)          | **Yes**          | Sorting in place (use `.toSorted()` for immutable) |
| `.includes(val)`    | `boolean`                    | No               | "Is this exact value in the array?"                |
| `.flat(depth)`      | New array (flattened)        | No               | Removing nesting levels                            |
| `.flatMap(fn)`      | New array (mapped + flat(1)) | No               | Map where each element expands to multiple items   |

### Chaining

```javascript theme={null}
const result = [1, 2, 3, 4, 5]
    .filter(n => n % 2 === 0)  // [2, 4]
    .map(n => n ** 2)          // [4, 16]
    .reduce((a, b) => a + b);  // 20
```

***

## 7. IIFE (Immediately Invoked Function Expression)

A function that runs immediately after it is defined. Used to create a private scope. Before ES6 modules existed, IIFEs were the *only* way to avoid polluting the global scope -- every major library (jQuery, Lodash, Backbone) was wrapped in one.

```javascript theme={null}
// Classic IIFE -- the outer parentheses tell JavaScript this is an expression,
// not a declaration. The trailing () immediately invokes it.
(function() {
    const secret = 'hidden'; // Not accessible outside this function
    console.log('IIFE executed');
})();

// Arrow function version
(() => {
    console.log('Arrow IIFE');
})();
```

<Tip>
  **Modern note**: With ES6 modules (`import`/`export`) and block-scoped `let`/`const`, IIFEs are far less common in new code. But you will still encounter them in legacy codebases and in patterns where you need to execute setup logic immediately with a contained scope.
</Tip>

***

## Summary

* **Function Types**: Declarations are hoisted, expressions are not. Arrow functions are concise.
* **Scope**: Global → Function → Block. JavaScript uses lexical (static) scoping.
* **Closures**: Functions remember their lexical environment. Use for data privacy.
* **Higher-Order Functions**: `map`, `filter`, `reduce` are your bread and butter.
* **Call Stack**: LIFO structure for managing function execution.

Next, we'll explore **Objects & Prototypes**, the foundation of JavaScript's object model.

***

## Interview Deep-Dive

<AccordionGroup>
  <Accordion title="Explain closures to me like I am a senior engineer who has never written JavaScript. Then tell me how they can cause memory leaks.">
    **Strong Answer:**

    * A closure is a function bundled together with references to its surrounding lexical environment. When a function is defined inside another function, the inner function retains access to the outer function's variables even after the outer function has returned and its execution context has been popped off the call stack. The runtime keeps those variables alive as long as the inner function exists.
    * In implementation terms, when V8 creates a function, it attaches a hidden `[[Environment]]` reference pointing to the lexical environment where the function was defined. That environment object holds the variable bindings. If the inner function references `count` from the outer scope, `count` is stored in a "context" object on the heap, not on the stack. The stack frame for the outer function is deallocated, but the heap-allocated context survives because the inner function still points to it.
    * Memory leak scenario: if you create a closure inside an event listener or a `setInterval`, and you never remove the listener or clear the interval, the closure keeps its entire enclosing scope alive indefinitely. I have debugged a production leak where a `setInterval` callback inside a React component captured a large `data` array from the component's scope. The component unmounted, but the interval was never cleared. Every 5 seconds, the callback ran, holding a reference to a 50MB dataset that could never be garbage collected. After a few hours, the browser tab consumed 2GB of memory.
    * The fix is always cleanup: `clearInterval`, `removeEventListener`, `AbortController` for fetch, or React's `useEffect` cleanup return. The pattern is: if a closure outlives the scope that created it (which is the whole point of closures), you must have a plan for when to release it.

    **Follow-up: In the classic loop-with-var closure problem, explain precisely WHY `var` causes all callbacks to print the same value, at the specification level.**

    With `var`, the loop `for (var i = 0; i < 3; i++)` declares `i` in the function scope (not the block scope). There is exactly one `i` variable shared across all iterations. Each `setTimeout` callback creates a closure over that same `i`. By the time the callbacks execute (after the synchronous loop completes), `i` has been incremented to `3`. All three callbacks read the same `i`, which is now `3`. With `let`, the ECMAScript spec mandates that each iteration of a `for` loop creates a new lexical environment with a fresh binding for `i`. So each callback closes over a different `i` binding with the value at the time of that specific iteration: 0, 1, 2. The pre-ES6 workaround was an IIFE: `(function(j) { setTimeout(() => console.log(j), 100); })(i)` -- the IIFE creates a new function scope for each iteration with its own `j` parameter.
  </Accordion>

  <Accordion title="What is the difference between the call stack and the execution context? Walk me through exactly what happens when a function is called.">
    **Strong Answer:**

    * The call stack is a LIFO data structure that tracks which function is currently executing. Each entry on the stack is an execution context. An execution context is the environment in which code is evaluated -- it contains the variable environment (where `var` declarations live), the lexical environment (where `let`/`const` declarations live), the `this` binding, and a reference to the outer lexical environment (for scope chain lookups).
    * When a function is called, the engine: (1) creates a new execution context for that function, (2) pushes it onto the call stack, (3) sets up the variable environment (hoists `var` declarations and function declarations), (4) initializes `let`/`const` bindings (but leaves them uninitialized -- the TDZ), (5) determines the `this` value based on how the function was called, (6) begins executing the function body line by line, (7) when the function returns (or throws), the execution context is popped off the stack.
    * The scope chain is built through lexical environments. Each execution context's lexical environment has an "outer reference" pointing to the lexical environment of the enclosing scope. When the engine looks up a variable, it walks this chain: current environment, then outer, then outer's outer, until it reaches the global environment. If not found, it throws a `ReferenceError`.
    * In practice, you encounter the call stack most directly when debugging. The call stack in Chrome DevTools shows you the chain of execution contexts. A `RangeError: Maximum call stack size exceeded` means you have pushed more contexts than the engine's limit (typically around 10,000-15,000 frames in V8, though it depends on the size of each frame).

    **Follow-up: How does tail call optimization (TCO) relate to the call stack, and does JavaScript support it?**

    Tail call optimization means that if a function's last action is calling another function (a "tail position" call), the engine can reuse the current stack frame instead of pushing a new one. This would make recursive algorithms like `factorial(100000)` possible without blowing the stack. ES6 formally specifies TCO (called "Proper Tail Calls"), but in practice, only Safari/JavaScriptCore implements it. V8 (Chrome, Node.js) and SpiderMonkey (Firefox) chose not to implement it, citing concerns about developer tooling (stack traces become useless when frames are reused) and implicit performance cliffs. The practical implication: do not rely on TCO in JavaScript. If you need deep recursion, convert to an iterative approach with an explicit stack (an array you push to and pop from) or use trampolining (a pattern where a recursive function returns a thunk instead of calling itself, and a loop repeatedly invokes the thunks).
  </Accordion>

  <Accordion title="When would you choose a regular function over an arrow function, and vice versa? Give me specific scenarios where using the wrong one causes bugs.">
    **Strong Answer:**

    * Arrow functions: use for callbacks, array method chains (`.map`, `.filter`, `.reduce`), and any context where you want to inherit `this` from the enclosing scope. They are concise, and the lexical `this` binding eliminates the most common class of `this` bugs.
    * Regular functions: use for object methods (where you need `this` to be the object), constructors (arrow functions cannot be used with `new`), and functions that need the `arguments` object (arrow functions do not have one).
    * Bug scenario 1 -- arrow function as an object method: `const obj = { name: "Alice", greet: () => this.name }`. Calling `obj.greet()` returns `undefined` (or throws in strict mode) because the arrow function captures `this` from the enclosing scope (the module or global scope), not from `obj`. The fix is `greet() { return this.name; }` (method shorthand).
    * Bug scenario 2 -- regular function as a callback inside a method: `person.listFriends = function() { this.friends.forEach(function(friend) { console.log(this.name + " knows " + friend); }); }`. The inner `function` has its own `this`, which is `undefined` in strict mode. The fix is either an arrow function (`this.friends.forEach((friend) => {...})`) or `.bind(this)`.
    * Bug scenario 3 -- arrow function with `prototype`: `const Foo = () => {}; Foo.prototype` is `undefined`. Arrow functions do not have a `prototype` property and cannot be used as constructors. `new Foo()` throws `TypeError: Foo is not a constructor`.
    * In practice, my rule is: arrow for lambdas, regular for anything that needs its own `this` or `arguments` or will be called with `new`.

    **Follow-up: What happens if you define a generator function as an arrow function?**

    You cannot. There is no `=>*` syntax in JavaScript. Arrow functions cannot be generators. If you try `const gen = *() => { yield 1; }`, you get a `SyntaxError`. You must use `function*` syntax: `const gen = function*() { yield 1; }` or `function* gen() { yield 1; }`. This is a deliberate language design choice -- generators need their own execution context that can be suspended and resumed, which conflicts with the lightweight, lexically-bound nature of arrow functions.
  </Accordion>

  <Accordion title="Explain higher-order functions. Then implement a basic version of Array.prototype.map from scratch.">
    **Strong Answer:**

    * A higher-order function is a function that either (a) takes one or more functions as arguments, or (b) returns a function. In JavaScript, this is possible because functions are first-class values -- they can be stored in variables, passed as arguments, and returned from other functions, just like numbers or strings.
    * Common higher-order functions: `Array.prototype.map` (takes a transform function), `Array.prototype.filter` (takes a predicate function), `setTimeout` (takes a callback), `addEventListener` (takes a handler). Factory functions like `debounce` and `throttle` are higher-order because they accept a function and return a new function with modified behavior.
    * A basic `map` implementation:

    ```javascript theme={null}
    Array.prototype.myMap = function(callback, thisArg) {
      const result = new Array(this.length);
      for (let i = 0; i < this.length; i++) {
        // Check for sparse array holes -- map should preserve them
        if (i in this) {
          result[i] = callback.call(thisArg, this[i], i, this);
        }
      }
      return result;
    };
    ```

    * The key details that separate a strong answer: (1) `callback.call(thisArg, ...)` -- the real `map` accepts an optional `thisArg` as the second argument to `map`, not just the callback. (2) The `i in this` check handles sparse arrays -- `[1, , 3].map(x => x * 2)` should produce `[2, empty, 6]`, not `[2, undefined, 6]`. (3) The callback receives three arguments: the current element, the index, and the original array. (4) `map` always returns a new array of the same length -- it does not mutate the original.
    * Performance nuance: in a hot path iterating over 100,000 elements, `.map().filter().reduce()` creates two intermediate arrays. A single `for` loop or a single `.reduce()` that combines all operations is more memory-efficient. But for typical use cases (hundreds to low thousands of elements), the clarity of chaining wins over the micro-optimization.

    **Follow-up: What is the difference between `.map()` and `.forEach()`? Can you use `.map()` everywhere you would use `.forEach()`?**

    `.map()` returns a new array with the transformed values. `.forEach()` returns `undefined` and is used purely for side effects (logging, DOM manipulation, pushing to an external array). You can technically use `.map()` where you would use `.forEach()`, but it is a code smell: you are creating and discarding an array for no reason, which signals to other developers that the return value matters when it does not. Linting rules like `no-unused-expressions` or `array-callback-return` will flag this. The reverse is not true: you cannot use `.forEach()` where you need `.map()` because `.forEach()` does not return the transformed array. Also, `.forEach()` cannot be short-circuited (no `break` equivalent), while a `for...of` loop can.
  </Accordion>

  <Accordion title="What is an IIFE and why were they necessary before ES6? Are there still valid use cases today?">
    **Strong Answer:**

    * An IIFE (Immediately Invoked Function Expression) is a function that is defined and executed in one step: `(function() { ... })()`. The outer parentheses force JavaScript to treat the `function` keyword as an expression (not a declaration), and the trailing `()` immediately invoke it.
    * Before ES6, JavaScript had no module system and only function-level scope (no block scope). The only way to create a private scope and avoid polluting the global namespace was to wrap code in a function. Every major pre-ES6 library (jQuery, Lodash, Backbone, Angular 1.x) was wrapped in an IIFE. The revealing module pattern -- `const module = (function() { let private = 0; return { getPrivate: () => private }; })()` -- was the standard way to achieve encapsulation.
    * Modern valid use cases still exist: (1) In scripts that are not ES modules (plain `<script>` tags without `type="module"`), an IIFE still provides scope isolation. (2) When you need to `await` at the top level in an environment that does not support top-level await, you use an async IIFE: `(async () => { const data = await fetch(...); })()`. (3) In some build tool configurations and legacy codebases, IIFEs are still the output format for bundled code.
    * In a modern ES module environment with `let`/`const`, IIFEs are rarely needed. Block scoping with `{}` and `let`/`const` provides the same isolation that IIFEs provided with `var`. If you see an IIFE in modern code, it is usually either legacy or the async IIFE pattern.

    **Follow-up: What is the difference between `(function(){})()` and `(function(){}())` -- and does it matter?**

    Both work identically. The first invokes the function outside the grouping parentheses; the second invokes it inside. Douglas Crockford (of "JavaScript: The Good Parts" fame) preferred the inner invocation style, arguing it makes the intent clearer by keeping the invocation visually inside the expression. In practice, it makes zero functional difference -- the parser handles both the same way. Most modern code uses the first style. The truly important detail is the outer parentheses: without them, `function(){}()` is a syntax error because JavaScript sees `function` at the start of a statement and expects a declaration (which requires a name).
  </Accordion>
</AccordionGroup>
