> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/web/js/val/func/closure/scopes-matter-with-closures.md).

# scopes matter with closures

[JS](/web/js.md) ⟩ [value](/web/js/val.md) ⟩ [function](/web/js/val/func.md) ⟩ [closure](/web/js/val/func/closure.md) ⟩ scopes matter

{% hint style="warning" %}
it matters <mark style="color:yellow;">**from which**</mark> [scope](/web/js/scope.md) your [closure](/web/js/val/func/closure.md) <mark style="color:yellow;">**closes over**</mark> [variable](/web/js/variable.md)s.
{% endhint %}

{% tabs %}
{% tab title="⭐️ 重點" %}
{% hint style="info" %}
the <mark style="color:yellow;">**scoping effect**</mark> of the <mark style="color:orange;">**initialization block**</mark> can be understood as if the <mark style="color:yellow;">**declaration**</mark> happens <mark style="color:yellow;">**within the loop body**</mark>, but just happens to be <mark style="color:yellow;">**accessible**</mark> within the <mark style="color:blue;">`condition`</mark> and <mark style="color:blue;">`update`</mark> parts.

📘 [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for#lexical_declarations_in_the_initialization_block_is_scoped_to_the_for_loop)
{% endhint %}
{% endtab %}

{% tab title="💈範例" %}

* replit：[scopes matter with closures](https://replit.com/@pegasusroe/scopes-matter-with-closures#index.js)

```javascript
const { log } = console;

//   ╭── i ──╮ <--- ⭐ `i` is "block-scoped"
for (let i = 0; i < 3; i++) {
    // ⭐ every time "block scope" is entered,
    //    a new/different `i` is captured by closure.
    //
    //         ╭─ closure ──╮
    setTimeout( () => log(i) , 1000);    // 0, 1, 2 ⭐ 
}

let j = 0;    // ❗ `j` is in "outer scope"

for (  ; j < 3; j++) {
    // ❗ every closure is capturing the same `j` variable
    //
    //         ╭─ closure ──╮
    setTimeout( () => log(j) , 2000);    // 3, 3, 3 ❗ (j = 3 after for-loop)
}

var keep1 = [];

//   ╭── i ──╮ <--- ❗ "var" has no block scope
for (var i = 0; i < 3; i++) {
    // ❗ every closure is keeping the "same" `i`.
    keep1[i] = function keepI(){
        return i;
    };
}

var keep2 = [];

//   ╭── i ──╮ <--- ⭐ "let" is block-scoped
for (let i = 0; i < 3; i++) {
    // ⭐ `i` is block-scoped, every time block scope is entered,
    //    a new/different `i` is created & kept by closure.
    keep2[i] = function keepI(){
        return i;
    };
}

[
    keep1.map(f => f()),    // ❗ [ 3, 3, 3 ]
    keep2.map(f => f()),    // ⭐ [ 0, 1, 2 ]
    
].forEach(x => log(x));
```

{% endtab %}

{% tab title="👥 相關" %}

* [for](/web/js/grammar/statement/loop/for/for.md) loop
  {% endtab %}

{% tab title="📘 手冊" %}

* [for](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for) ⟩ [initialization block syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for#initialization_block_syntax) ⟩
  * [Lexical declarations in the initialization block is scoped to the for loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for#lexical_declarations_in_the_initialization_block_is_scoped_to_the_for_loop)
* [Closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)
  {% endtab %}

{% tab title="❓" %}
{% hint style="warning" %}
如果如 ["for-init" scope](/web/js/grammar/statement/loop/for/for/for-init-scope.md) 中所說： [let](/web/js/variable/declare/let.md) 變數活在這個特殊的範圍中，那麼本例的 "i" 應該就活在這個範圍內，對內部的 "block scope" 來說，應該也算是一個 "outer scope"，照理說表現的方式應該要跟 "j" 一樣才是，但這裡的 "i" 表現得卻像是在 "block scope" 裏面才生出來的「新變數」一樣，實在有點怪❗️

所以看來，在實際使用上，"i" 的行為更像是 "[block-scoped](/web/js/grammar/statement/other/block/block.md)" 一些 ❓&#x20;
{% endhint %}
{% endtab %}
{% endtabs %}
