Why can a variable used inside a loop cause trouble elsewhere? Scope determines where a binding can be accessed. With `let`, a binding is visible in its containing block and nested blocks, but not outside. A block is the area between `{` and `}`; it can even stand on its own. section 4.1
A boundary you can see
if (true) { let foo = 'bar'; console.log(foo); // 'bar' } console.log(foo); // ReferenceError The first lookup is inside `foo`’s block. The second is outside it. By contrast, a `var` declared in the `if` block remains accessible elsewhere in its containing function. section 4.1
A `let` declared in a `for` clause belongs to the loop’s block: the body can use it, but code after the loop cannot. This differs from `var`’s function scope. section 4.1 section 4.4
Listing 4.2. There is a scope problem here, but what is it?
In the list-item click-handler example, `var` leaves the loop’s `li` and `i` bindings shared across handlers. Check their values when a click actually occurs, not just when the handler is attached. section 4.1
Listing 4.1. Using a free-standing block to keep a variable private
A free-standing block keeps `data` inaccessible from outside, while the `read` and `write` functions created inside can continue to use it. Block scope can protect a working variable without wrapping the block in another function. section 4.1
Scope does not make early access safe: reading a `let` binding before its declaration throws, whereas an early read of `var` yields `undefined`. When changing existing code, do not replace every `var` mechanically; first check where each binding is used. section 4.3
Quick practice
In a range-generating function, identify the temporary swap value and loop counter. Put each `let` declaration in the block where it is needed, then check whether the IIFEs formerly used to hide those variables are still necessary. section 4.4




















