IIFEs
In short: an Immediately Invoked Function Expression wraps code in
(function () { ... }) and calls it on the spot with a trailing () —
the parentheses around the function turn it into an expression, and the
second pair calls it immediately, once. Anything declared inside —
let, const, even other functions — lives in a scope that's locked from
the outside the moment the IIFE finishes running. This was how JavaScript
faked private state before real modules existed, and it still shows up in
scripts that want to avoid leaking names into the global scope.

A value that never escapes
The simplest IIFE: a value that exists only for the moment the function runs, then disappears.
Inside the IIFE, secret is perfectly normal. The moment the function
finishes, that scope is gone — secret was never declared anywhere
reachable from outside, so asking for it throws a ReferenceError, the
same as asking for a name that never existed.
A counter with genuinely private state
The useful pattern: return an object from the IIFE, so callers get controlled access without ever touching the private variable directly.
count lives inside the IIFE's locked scope — there's no counter.count
to read or overwrite by accident. increment and value were defined
inside that same scope, so they keep access to count through closure,
even after the IIFE itself has already finished running.
An arrow function works too
Any function expression can be immediately invoked, including an arrow:
The shape is the same — wrap it so it's an expression, then call it right
there. Arrow IIFEs are common in modern code for a quick one-off scope
with less punctuation than the classic function version.
Quick practice
What makes (function () { ... })() run immediately, instead of just being defined?
After (function () { let x = 5; })(); runs, what does console.log(x) do outside it?
Why does an IIFE-returned object's method still work after the IIFE itself has finished running?
