πŸ“¦ leonardomso / 33-js-concepts

πŸ“„ scope-and-closures.mdx Β· 1190 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190---
title: "Scope & Closures"
sidebarTitle: "Scope and Closures: How Variables Really Work"
description: "Learn JavaScript scope and closures. Understand var vs let vs const, lexical scoping, the scope chain, and closure patterns."
---

Why can some variables be accessed from anywhere in your code, while others seem to disappear? How do functions "remember" variables from their parent functions, even after those functions have finished running?

```javascript
function createCounter() {
  let count = 0  // This variable is "enclosed"
  
  return function() {
    count++
    return count
  }
}

const counter = createCounter()
console.log(counter())  // 1
console.log(counter())  // 2 β€” it remembers!
```

The answers lie in understanding **scope** and **closures**. These two fundamental concepts govern how variables work in JavaScript. Scope determines *where* variables are visible, while closures allow functions to *remember* their original environment.

<Info>
**What you'll learn in this guide:**
- The 3 types of scope: global, function, and block
- How [`var`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var), [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let), and [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) behave differently
- What lexical scope means and how the scope chain works
- What closures are and why every JavaScript developer must understand them
- Practical patterns: data privacy, factories, and memoization
- The classic closure gotchas and how to avoid them
</Info>

<Warning>
**Prerequisite:** This guide builds on your understanding of the [call stack](/concepts/call-stack). Knowing how JavaScript tracks function execution will help you understand how scope and closures work under the hood.
</Warning>

---

## What is Scope in JavaScript?

**[Scope](https://developer.mozilla.org/en-US/docs/Glossary/Scope)** is the current context of execution in which values and expressions are "visible" or can be referenced. It's the set of rules that determines where and how variables can be accessed in your code. If a variable is not in the current scope, it cannot be used. Scopes can be nested, and inner scopes have access to outer scopes, but not vice versa.

---

## The Office Building Analogy

Imagine it's after hours and you're wandering through your office building (legally, you work there, promise). You notice something interesting about what you can and can't see:

- **Inside your private office**, you can see everything on your desk, peek into the hallway through your door, and even see the lobby through the glass walls
- **In the hallway**, you can see the lobby clearly, but those private offices? Their blinds are shut. No peeking allowed
- **In the lobby**, you're limited to just what's there: the reception desk, some chairs, maybe a sad-looking plant

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ LOBBY (Global Scope)                                        β”‚
β”‚   reception = "Welcome Desk"                                β”‚
β”‚                                                             β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚   β”‚ HALLWAY (Function Scope)                          β”‚     β”‚
β”‚   β”‚   hallwayPlant = "Fern"                           β”‚     β”‚
β”‚   β”‚                                                   β”‚     β”‚
β”‚   β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚     β”‚
β”‚   β”‚   β”‚ PRIVATE OFFICE (Block Scope)          β”‚       β”‚     β”‚
β”‚   β”‚   β”‚   secretDocs = "Confidential"         β”‚       β”‚     β”‚
β”‚   β”‚   β”‚                                       β”‚       β”‚     β”‚
β”‚   β”‚   β”‚   Can see: secretDocs      βœ“          β”‚       β”‚     β”‚
β”‚   β”‚   β”‚   Can see: hallwayPlant    βœ“          β”‚       β”‚     β”‚
β”‚   β”‚   β”‚   Can see: reception       βœ“          β”‚       β”‚     β”‚
β”‚   β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚     β”‚
β”‚   β”‚                                                   β”‚     β”‚
β”‚   β”‚   Cannot see: secretDocs       βœ—                  β”‚     β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                                                             β”‚
β”‚   Cannot see: hallwayPlant, secretDocs  βœ—                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

This is exactly how **scope** works in JavaScript! Code in inner scopes can "look out" and access variables from outer scopes, but outer scopes can never "look in" to inner scopes.

And here's where it gets really interesting: imagine someone who worked in that private office quits and leaves the building. But they took a mental snapshot of everything in there: the passwords on sticky notes, the secret project plans, the snack drawer location. Even though they've left, they still *remember* everything. That's essentially what a **closure** is: a function that "remembers" the scope where it was created, even after that scope is gone.

### Why Does Scope Exist?

Scope exists for three critical reasons:

<AccordionGroup>
  <Accordion title="1. Preventing Naming Conflicts">
    Without scope, every variable would be global. Imagine the chaos if every `i` in every `for` loop had to have a unique name!
    
    ```javascript
    function countApples() {
      let count = 0;  // This 'count' is separate...
      // ...
    }
    
    function countOranges() {
      let count = 0;  // ...from this 'count'
      // ...
    }
    ```
  </Accordion>
  
  <Accordion title="2. Memory Management">
    When a scope ends, variables declared in that scope can be [garbage collected](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management#garbage_collection) (cleaned up from memory). This keeps your program efficient.
    
    ```javascript
    function processData() {
      let hugeArray = new Array(1000000);  // Takes memory
      // ... process it
    }  // hugeArray can now be garbage collected
    ```
  </Accordion>
  
  <Accordion title="3. Encapsulation & Security">
    Scope allows you to hide implementation details and protect data from being accidentally modified.
    
    ```javascript
    function createBankAccount() {
      let balance = 0;  // Private! Can't be accessed directly
      
      return {
        deposit(amount) { balance += amount; },
        getBalance() { return balance; }
      };
    }
    ```
  </Accordion>
</AccordionGroup>

---

## The Three Types of Scope

JavaScript has three main types of scope. Understanding each one is fundamental to writing predictable code.

<Note>
ES6 modules also introduce **module scope**, where top-level variables are scoped to the module rather than being global. Learn more in our [IIFE, Modules and Namespaces](/concepts/iife-modules) guide.
</Note>

### 1. Global Scope

Variables declared outside of any function or block are in the **global scope**. They're accessible from anywhere in your code.

```javascript
// Global scope
const appName = "MyApp";
let userCount = 0;

function greet() {
  console.log(appName);  // βœ“ Can access global variable
  userCount++;           // βœ“ Can modify global variable
}

if (true) {
  console.log(appName);  // βœ“ Can access global variable
}
```

#### The Global Object

In browsers, global variables become properties of the [`window`](https://developer.mozilla.org/en-US/docs/Web/API/Window) object. In Node.js, they attach to `global`. The modern, universal way to access the global object is [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis).

```javascript
var oldSchool = "I'm on window";      // window.oldSchool (var only)
let modern = "I'm NOT on window";      // NOT on window

console.log(window.oldSchool);         // "I'm on window"
console.log(window.modern);            // undefined
console.log(globalThis);               // Works everywhere
```

<Warning>
**Avoid Global Pollution!** Too many global variables lead to naming conflicts, hard-to-track bugs, and code that's difficult to maintain. Keep your global scope clean.

```javascript
// Bad: Polluting global scope
var userData = {};
var settings = {};
var helpers = {};

// Good: Use a single namespace
const MyApp = {
  userData: {},
  settings: {},
  helpers: {}
};
```
</Warning>

---

### 2. Function Scope

Variables declared with [`var`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var) inside a function are **function-scoped**. They're only accessible within that function.

```javascript
function calculateTotal() {
  var subtotal = 100;
  var tax = 10;
  var total = subtotal + tax;
  
  console.log(total);  // βœ“ 110
}

calculateTotal();
// console.log(subtotal);  // βœ— ReferenceError: subtotal is not defined
```

#### var Hoisting

Variables declared with `var` are "hoisted" to the top of their function. This means JavaScript knows about them before the code runs, but they're initialized as `undefined` until the actual declaration line.

```javascript
function example() {
  console.log(message);  // undefined (not an error!)
  var message = "Hello";
  console.log(message);  // "Hello"
}

// JavaScript interprets this as:
function exampleHoisted() {
  var message;           // Declaration hoisted to top
  console.log(message);  // undefined
  message = "Hello";     // Assignment stays in place
  console.log(message);  // "Hello"
}
```

<Tip>
**Hoisting Visualization:**

```
Your code:                    How JS sees it:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ function foo() {    β”‚       β”‚ function foo() {    β”‚
β”‚                     β”‚       β”‚   var x;  // hoistedβ”‚
β”‚   console.log(x);   β”‚  ──►  β”‚   console.log(x);   β”‚
β”‚   var x = 5;        β”‚       β”‚   x = 5;            β”‚
β”‚ }                   β”‚       β”‚ }                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
</Tip>

---

### 3. Block Scope

Variables declared with [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) and [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) are **block-scoped**. A block is any code within curly braces `{}`: if statements, for loops, while loops, or just standalone blocks.

```javascript
if (true) {
  let blockLet = "I'm block-scoped";
  const blockConst = "Me too";
  var functionVar = "I escape the block!";
}

// console.log(blockLet);    // βœ— ReferenceError
// console.log(blockConst);  // βœ— ReferenceError
console.log(functionVar);    // βœ“ "I escape the block!"
```

#### The Temporal Dead Zone (TDZ)

Unlike `var`, variables declared with `let` and `const` are not initialized until their declaration is evaluated. Accessing them before declaration causes a [`ReferenceError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError). This period is called the **Temporal Dead Zone**.

```javascript
function demo() {
  // TDZ for 'name' starts here
  
  console.log(name);  // ReferenceError: Cannot access 'name' before initialization
  
  let name = "Alice"; // TDZ ends here
  
  console.log(name);  // "Alice"
}
```

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                                                            β”‚
β”‚   function demo() {                                        β”‚
β”‚                                                            β”‚
β”‚     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚     β”‚           TEMPORAL DEAD ZONE                   β”‚     β”‚
β”‚     β”‚                                                β”‚     β”‚
β”‚     β”‚   'name' exists but cannot be accessed yet!    β”‚     β”‚
β”‚     β”‚                                                β”‚     β”‚
β”‚     β”‚   console.log(name);  // ReferenceError        β”‚     β”‚
β”‚     β”‚                                                β”‚     β”‚
β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β”‚                           β”‚                                β”‚
β”‚                           β–Ό                                β”‚
β”‚     let name = "Alice";   // TDZ ends here                 β”‚
β”‚                                                            β”‚
β”‚     console.log(name);    // "Alice" - works fine!         β”‚
β”‚                                                            β”‚
β”‚   }                                                        β”‚
β”‚                                                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

<Note>
The TDZ exists to catch programming errors. It's actually a good thing! It prevents you from accidentally using variables before they're ready.
</Note>

---

## var vs let vs const

Here's a comprehensive comparison of the three variable declaration keywords:

| Feature | `var` | `let` | `const` |
|---------|-------|-------|---------|
| **Scope** | Function | Block | Block |
| **Hoisting** | Yes (initialized as `undefined`) | Yes (but TDZ) | Yes (but TDZ) |
| **Redeclaration** | βœ“ Allowed | βœ— Error | βœ— Error |
| **Reassignment** | βœ“ Allowed | βœ“ Allowed | βœ— Error |
| **Must Initialize** | No | No | Yes |

<Tabs>
  <Tab title="Redeclaration">
    ```javascript
    // var allows redeclaration (can cause bugs!)
    var name = "Alice";
    var name = "Bob";     // No error, silently overwrites
    console.log(name);    // "Bob"
    
    // let and const prevent redeclaration
    let age = 25
    // let age = 30      // SyntaxError: 'age' has already been declared
    
    const PI = 3.14
    // const PI = 3.14159 // SyntaxError
    ```
  </Tab>
  <Tab title="Reassignment">
    ```javascript
    // var and let allow reassignment
    var count = 1;
    count = 2;           // βœ“ Fine
    
    let score = 100;
    score = 200;         // βœ“ Fine
    
    // const prevents reassignment
    const API_KEY = "abc123"
    // API_KEY = "xyz789"  // TypeError: Assignment to constant variable
    
    // BUT: const objects/arrays CAN be mutated!
    const user = { name: "Alice" }
    user.name = "Bob"   // βœ“ This works!
    user.age = 25       // βœ“ This works too!
    // user = {}        // βœ— This fails (reassignment)
    ```
  </Tab>
  <Tab title="Hoisting Behavior">
    ```javascript
    function hoistingDemo() {
      // var: hoisted and initialized as undefined
      console.log(a);  // undefined
      var a = 1;
      
      // let: hoisted but NOT initialized (TDZ)
      // console.log(b);  // ReferenceError!
      let b = 2;
      
      // const: same as let
      // console.log(c);  // ReferenceError!
      const c = 3;
    }
    ```
  </Tab>
</Tabs>

### The Classic for-loop Problem

This is one of the most common JavaScript gotchas, and it perfectly illustrates why `let` is preferred over `var`:

```javascript
// The Problem: var is function-scoped
for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i)
  }, 100)
}
// Output: 3, 3, 3  (not 0, 1, 2!)

// Why? There's only ONE 'i' variable shared across all iterations.
// By the time the setTimeout callbacks run, the loop has finished and i === 3.
```

The [`setTimeout()`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) callbacks all close over the same `i` variable, which equals `3` by the time they execute. (To understand why the callbacks don't run immediately, see our [Event Loop](/concepts/event-loop) guide.)

```javascript
// The Solution: let is block-scoped
for (let i = 0; i < 3; i++) {
  setTimeout(() => {
    console.log(i)
  }, 100)
}
// Output: 0, 1, 2  (correct!)

// Why? Each iteration gets its OWN 'i' variable.
// Each setTimeout callback closes over a different 'i'.
```

<Tip>
**Modern Best Practice:**
1. Use `const` by default
2. Use `let` when you need to reassign
3. Avoid `var` entirely (legacy code only)

This approach catches bugs at compile time and makes your intent clear.
</Tip>

---

## Lexical Scope

**Lexical scope** (also called **static scope**) means that the scope of a variable is determined by its position in the source code, not by how functions are called at runtime.

```javascript
const outer = "I'm outside!";

function outerFunction() {
  const middle = "I'm in the middle!";
  
  function innerFunction() {
    const inner = "I'm inside!";
    
    // innerFunction can access all three variables
    console.log(inner);   // βœ“ Own scope
    console.log(middle);  // βœ“ Parent scope
    console.log(outer);   // βœ“ Global scope
  }
  
  innerFunction();
  // console.log(inner);  // βœ— ReferenceError
}

outerFunction();
// console.log(middle);   // βœ— ReferenceError
```

### The Scope Chain

When JavaScript needs to find a variable, it walks up the **scope chain**. It starts from the current scope and moves outward until it finds the variable or reaches the global scope.

<Steps>
  <Step title="Look in Current Scope">
    JavaScript first checks if the variable exists in the current function/block scope.
  </Step>
  
  <Step title="Look in Parent Scope">
    If not found, it checks the enclosing (parent) scope.
  </Step>
  
  <Step title="Continue Up the Chain">
    This process continues up through all ancestor scopes.
  </Step>
  
  <Step title="Reach Global Scope">
    Finally, it checks the global scope. If still not found, a `ReferenceError` is thrown.
  </Step>
</Steps>

```
Variable Lookup: Where is 'x'?

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Global Scope                                    β”‚
β”‚   x = "global"                                  β”‚
β”‚                                                 β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚   β”‚ outer() Scope                           β”‚   β”‚
β”‚   β”‚   x = "outer"                           β”‚   β”‚
β”‚   β”‚                                         β”‚   β”‚
β”‚   β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚   β”‚   β”‚ inner() Scope                   β”‚   β”‚   β”‚
β”‚   β”‚   β”‚                                 β”‚   β”‚   β”‚
β”‚   β”‚   β”‚   console.log(x);               β”‚   β”‚   β”‚
β”‚   β”‚   β”‚         β”‚                       β”‚   β”‚   β”‚
β”‚   β”‚   β”‚         β–Ό                       β”‚   β”‚   β”‚
β”‚   β”‚   β”‚   1. Check inner() β†’ not found  β”‚   β”‚   β”‚
β”‚   β”‚   β”‚         β”‚                       β”‚   β”‚   β”‚
β”‚   β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚   β”‚             β–Ό                           β”‚   β”‚
β”‚   β”‚   2. Check outer() β†’ FOUND! "outer"     β”‚   β”‚
β”‚   β”‚                                         β”‚   β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Result: "outer"
```

### Variable Shadowing

When an inner scope declares a variable with the same name as an outer scope, the inner variable "shadows" the outer one:

```javascript
const name = "Global";

function greet() {
  const name = "Function";  // Shadows global 'name'
  
  if (true) {
    const name = "Block";   // Shadows function 'name'
    console.log(name);      // "Block"
  }
  
  console.log(name);        // "Function"
}

greet();
console.log(name);          // "Global"
```

<Warning>
Shadowing can be confusing. While sometimes intentional, accidental shadowing is a common source of bugs. Many linters warn about this.
</Warning>

---

## What is a Closure in JavaScript?

A **[closure](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures)** is the combination of a function bundled together with references to its surrounding state (the lexical environment). In other words, a closure gives a function access to variables from an outer (enclosing) scope, even after that outer function has finished executing and returned. Every function in JavaScript creates a closure at creation time.

Remember our office building analogy? A closure is like someone who worked in the private office, left the building, but still remembers exactly where everything was, and can still use that knowledge!

### Every Function Creates a Closure

In JavaScript, closures are created automatically every time you create a function. The function maintains a reference to its lexical environment.

```javascript
function createGreeter(greeting) {
  // 'greeting' is in createGreeter's scope
  
  return function(name) {
    // This inner function is a closure!
    // It "closes over" the 'greeting' variable
    console.log(`${greeting}, ${name}!`);
  };
}

const sayHello = createGreeter("Hello");
const sayHola = createGreeter("Hola");

// createGreeter has finished executing, but...
sayHello("Alice");  // "Hello, Alice!"
sayHola("Bob");     // "Hola, Bob!"

// The inner functions still remember their 'greeting' values!
```

### How Closures Work: Step by Step

<Steps>
  <Step title="Outer Function is Called">
    `createGreeter("Hello")` is called. A new execution context is created with `greeting = "Hello"`.
  </Step>
  
  <Step title="Inner Function is Created">
    The inner function is created. It captures a reference to the current lexical environment (which includes `greeting`).
  </Step>
  
  <Step title="Outer Function Returns">
    `createGreeter` returns the inner function and its execution context is (normally) cleaned up.
  </Step>
  
  <Step title="But the Closure Survives!">
    Because the inner function holds a reference to the lexical environment, the `greeting` variable is NOT garbage collected. It survives!
  </Step>
  
  <Step title="Closure is Invoked Later">
    When `sayHello("Alice")` is called, the function can still access `greeting` through its closure.
  </Step>
</Steps>

```
After createGreeter("Hello") returns:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ sayHello (Function)                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ [[Code]]: function(name) {...}       β”‚
β”‚                                      β”‚
β”‚ [[Environment]]: ────────────────────────┐
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
                                           β–Ό
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚ Lexical Environment        β”‚
                          β”‚ (Kept alive by closure!)   β”‚
                          β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
                          β”‚ greeting: "Hello"          β”‚
                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

---

## Closures in the Wild

Closures aren't just a theoretical concept. You'll use them every day. Here are the patterns that make closures so powerful.

### 1. Data Privacy & Encapsulation

Closures let you create truly private variables in JavaScript:

```javascript
function createCounter() {
  let count = 0;  // Private variable - no way to access directly!
  
  return {
    increment() {
      count++;
      return count;
    },
    decrement() {
      count--;
      return count;
    },
    getCount() {
      return count;
    }
  };
}

const counter = createCounter();

console.log(counter.getCount());  // 0
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1

// There's NO way to access 'count' directly!
console.log(counter.count);       // undefined
```

<Tip>
This pattern is the foundation of the **Module Pattern**, widely used before ES6 modules became available. Learn more in our [IIFE, Modules and Namespaces](/concepts/iife-modules) guide.
</Tip>

### 2. Function Factories

Closures let you create specialized functions on the fly:

```javascript
function createMultiplier(multiplier) {
  return function(number) {
    return number * multiplier;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);
const tenX = createMultiplier(10);

console.log(double(5));   // 10
console.log(triple(5));   // 15
console.log(tenX(5));     // 50

// Each function "remembers" its own multiplier
```

This pattern works great with the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) for creating reusable API clients:

```javascript
// Real-world example: API request factories
function createApiClient(baseUrl) {
  return {
    get(endpoint) {
      return fetch(`${baseUrl}${endpoint}`);
    },
    post(endpoint, data) {
      return fetch(`${baseUrl}${endpoint}`, {
        method: 'POST',
        body: JSON.stringify(data)
      });
    }
  };
}

const githubApi = createApiClient('https://api.github.com');
const myApi = createApiClient('https://myapp.com/api');

// Each client remembers its baseUrl
githubApi.get('/users/leonardomso');
myApi.get('/users/1');
```

### 3. Preserving State in Callbacks & Event Handlers

Closures are essential for maintaining state in asynchronous code. When you use [`addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to attach event handlers, those handlers can close over variables from their outer scope:

```javascript
function setupClickCounter(buttonId) {
  let clicks = 0;  // This variable persists across clicks!
  
  const button = document.getElementById(buttonId);
  
  button.addEventListener('click', function() {
    clicks++;
    console.log(`Button clicked ${clicks} time${clicks === 1 ? '' : 's'}`);
  });
}

setupClickCounter('myButton');
// Each click increments the same 'clicks' variable
// Click 1: "Button clicked 1 time"
// Click 2: "Button clicked 2 times"
// Click 3: "Button clicked 3 times"
```

### 4. Memoization (Caching Results)

Closures enable efficient caching of expensive computations:

```javascript
function createMemoizedFunction(fn) {
  const cache = {};  // Cache persists across calls!
  
  return function(arg) {
    if (arg in cache) {
      console.log('Returning cached result');
      return cache[arg];
    }
    
    console.log('Computing result');
    const result = fn(arg);
    cache[arg] = result;
    return result;
  };
}

// Expensive operation: calculate factorial
function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
}

const memoizedFactorial = createMemoizedFunction(factorial);

console.log(memoizedFactorial(5));  // Computing result β†’ 120
console.log(memoizedFactorial(5));  // Returning cached result β†’ 120
console.log(memoizedFactorial(5));  // Returning cached result β†’ 120
```

---

## Common Mistakes and Pitfalls

Understanding scope and closures means understanding where things go wrong. These are the mistakes that trip up even experienced developers.

### The #1 Closure Interview Question

This is the classic closure trap. Almost everyone gets it wrong the first time:

### The Problem

```javascript
// What does this print?
for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}

// Most people expect: 0, 1, 2
// Actual output: 3, 3, 3
```

### Why Does This Happen?

```
What actually happens:

  TIME ════════════════════════════════════════════════════►

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ IMMEDIATELY (milliseconds):                             β”‚
  β”‚                                                         β”‚
  β”‚   Loop iteration 1: i = 0, schedule callback            β”‚
  β”‚   Loop iteration 2: i = 1, schedule callback            β”‚
  β”‚   Loop iteration 3: i = 2, schedule callback            β”‚
  β”‚   Loop ends: i = 3                                      β”‚
  β”‚                                                         β”‚
  β”‚   All 3 callbacks point to the SAME 'i' variable ──┐    β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚β”€β”€β”€β”˜
                                                        β”‚
                                                        β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ ~1 SECOND LATER:                                        β”‚
  β”‚                                                         β”‚
  β”‚   callback1 runs: "What's i?" β†’ i is 3 β†’ prints 3       β”‚
  β”‚   callback2 runs: "What's i?" β†’ i is 3 β†’ prints 3       β”‚
  β”‚   callback3 runs: "What's i?" β†’ i is 3 β†’ prints 3       β”‚
  β”‚                                                         β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Result: 3, 3, 3 (not 0, 1, 2!)
```

### The Solutions

<Tabs>
  <Tab title="Solution 1: Use let">
    The simplest modern solution. `let` creates a new binding for each iteration:
    
    ```javascript
    for (let i = 0; i < 3; i++) {
      setTimeout(function() {
        console.log(i);
      }, 1000);
    }
    // Output: 0, 1, 2 βœ“
    ```
  </Tab>
  <Tab title="Solution 2: IIFE">
    Pre-ES6 solution using an Immediately Invoked Function Expression:
    
    ```javascript
    for (var i = 0; i < 3; i++) {
      (function(j) {
        setTimeout(function() {
          console.log(j);
        }, 1000);
      })(i);  // Pass i as argument, creating a new 'j' each time
    }
    // Output: 0, 1, 2 βœ“
    ```
  </Tab>
  <Tab title="Solution 3: forEach">
    Using array methods, which naturally create new scope per iteration:
    
    ```javascript
    [0, 1, 2].forEach(function(i) {
      setTimeout(function() {
        console.log(i);
      }, 1000);
    });
    // Output: 0, 1, 2 βœ“
    ```
  </Tab>
</Tabs>

### Memory Leaks from Closures

Closures are powerful, but they come with responsibility. Since closures keep references to their outer scope variables, those variables can't be [garbage collected](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management#garbage_collection).

### Potential Memory Leaks

```javascript
function createHeavyClosure() {
  const hugeData = new Array(1000000).fill('x');  // Large data
  
  return function() {
    // This reference to hugeData keeps the entire array in memory
    console.log(hugeData.length);
  };
}

const leakyFunction = createHeavyClosure();
// hugeData is still in memory because the closure references it
```

<Note>
Modern JavaScript engines like V8 can optimize closures that don't actually use outer variables. However, it's best practice to assume referenced variables are retained and explicitly clean up large data when you're done with it.
</Note>

### Breaking Closure References

When you're done with a closure, explicitly break the reference. Use [`removeEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener) to clean up event handlers:

```javascript
function setupHandler(element) {
  // Imagine this returns a large dataset
  const largeData = { users: new Array(10000).fill({ name: 'User' }) };
  
  const handler = function() {
    console.log(`Processing ${largeData.users.length} users`);
  };
  
  element.addEventListener('click', handler);
  
  // Return a cleanup function
  return function cleanup() {
    element.removeEventListener('click', handler);
    // Now handler and largeData can be garbage collected
  };
}

const button = document.getElementById('myButton');
const cleanup = setupHandler(button);

// Later, when you're done with this functionality:
cleanup();  // Removes listener, allows memory to be freed
```

<Tip>
**Best Practices:**
1. Don't capture more than you need in closures
2. Set closure references to `null` when done
3. Remove event listeners when components unmount
4. Be especially careful in loops and long-lived applications
</Tip>

---

## Key Takeaways

<Info>
**The key things to remember about Scope & Closures:**

1. **Scope = Variable Visibility** β€” It determines where variables can be accessed

2. **Three types of scope**: Global (everywhere), Function (`var`), Block (`let`/`const`)

3. **Lexical scope is static** β€” Determined by code position, not runtime behavior

4. **Scope chain** β€” JavaScript looks up variables from inner to outer scope

5. **`let` and `const` are block-scoped** β€” Prefer them over `var`

6. **Temporal Dead Zone** β€” `let`/`const` can't be accessed before declaration

7. **Closure = Function + Its Lexical Environment** β€” Functions "remember" where they were created

8. **Closures enable**: Data privacy, function factories, stateful callbacks, memoization

9. **Watch for the loop gotcha** β€” Use `let` instead of `var` in loops with async callbacks

10. **Mind memory** β€” Closures keep references alive; clean up when done
</Info>

---

## Test Your Knowledge

<AccordionGroup>
  <Accordion title="Question 1: What are the three types of scope in JavaScript?">
    **Answer:**
    
    1. **Global Scope** β€” Variables declared outside any function or block; accessible everywhere
    2. **Function Scope** β€” Variables declared with `var` inside a function; accessible only within that function
    3. **Block Scope** β€” Variables declared with `let` or `const` inside a block `{}`; accessible only within that block
    
    ```javascript
    const global = "everywhere";        // Global scope
    
    function example() {
      var functionScoped = "function";  // Function scope
      
      if (true) {
        let blockScoped = "block";      // Block scope
      }
    }
    ```
  </Accordion>
  
  <Accordion title="Question 2: What is the Temporal Dead Zone?">
    **Answer:** The Temporal Dead Zone (TDZ) is the period between entering a scope and the actual declaration of a `let` or `const` variable. During this time, the variable exists but cannot be accessed. Doing so throws a `ReferenceError`.
    
    ```javascript
    function example() {
      // TDZ starts for 'x'
      console.log(x);  // ReferenceError!
      // TDZ continues...
      let x = 10;      // TDZ ends
      console.log(x);  // 10 βœ“
    }
    ```
    
    The TDZ helps catch bugs where you accidentally use variables before they're initialized.
  </Accordion>
  
  <Accordion title="Question 3: What is lexical scope?">
    **Answer:** Lexical scope (also called static scope) means that the accessibility of variables is determined by their physical position in the source code at write time, not by how or where functions are called at runtime.
    
    Inner functions have access to variables declared in their outer functions because of where they are written, not because of when they're invoked.
    
    ```javascript
    function outer() {
      const message = "Hello";
      
      function inner() {
        console.log(message);  // Can access 'message' because of lexical scope
      }
      
      return inner;
    }
    
    const fn = outer();
    fn();  // "Hello" β€” still works even though outer() has returned
    ```
  </Accordion>
  
  <Accordion title="Question 4: What is a closure?">
    **Answer:** A closure is a function combined with references to its surrounding lexical environment. In simpler terms, a closure is a function that "remembers" the variables from the scope where it was created, even when executed outside that scope.
    
    ```javascript
    function createCounter() {
      let count = 0;  // This variable is "enclosed" in the closure
      
      return function() {
        count++;
        return count;
      };
    }
    
    const counter = createCounter();
    console.log(counter());  // 1
    console.log(counter());  // 2
    // 'count' persists because of the closure
    ```
    
    Every function in JavaScript creates a closure. The term usually refers to situations where this behavior is notably useful or surprising.
  </Accordion>
  
  <Accordion title="Question 5: What will this code output and why?">
    ```javascript
    for (var i = 0; i < 3; i++) {
      setTimeout(() => console.log(i), 100);
    }
    ```
    
    **Answer:** It outputs `3, 3, 3`.
    
    **Why?** Because `var` is function-scoped (not block-scoped), there's only ONE `i` variable shared across all iterations. By the time the `setTimeout` callbacks execute (after ~100ms), the loop has already completed and `i` equals `3`.
    
    **Fix:** Use `let` instead of `var`:
    ```javascript
    for (let i = 0; i < 3; i++) {
      setTimeout(() => console.log(i), 100);
    }
    // Outputs: 0, 1, 2
    ```
    
    With `let`, each iteration gets its own `i` variable, and each callback closes over a different value.
  </Accordion>
  
  <Accordion title="Question 6: When would you use a closure in real code?">
    **Answer:** Common practical uses for closures include:
    
    1. **Data Privacy** β€” Creating private variables that can't be accessed directly:
    ```javascript
    function createWallet(initial) {
      let balance = initial;
      return {
        spend(amount) { balance -= amount; },
        getBalance() { return balance; }
      };
    }
    ```
    
    2. **Function Factories** β€” Creating specialized functions:
    ```javascript
    function createTaxCalculator(rate) {
      return (amount) => amount * rate;
    }
    const calculateVAT = createTaxCalculator(0.20);
    ```
    
    3. **Maintaining State in Callbacks** β€” Event handlers, timers, API calls:
    ```javascript
    function setupLogger(prefix) {
      return (message) => console.log(`[${prefix}] ${message}`);
    }
    ```
    
    4. **Memoization/Caching** β€” Storing computed results:
    ```javascript
    function memoize(fn) {
      const cache = {};
      return (arg) => cache[arg] ?? (cache[arg] = fn(arg));
    }
    ```
  </Accordion>
</AccordionGroup>

---

## Related Concepts

<CardGroup cols={2}>
  <Card title="Call Stack" icon="layer-group" href="/concepts/call-stack">
    How JavaScript tracks function execution and manages scope
  </Card>
  <Card title="Hoisting" icon="arrow-up" href="/beyond/concepts/hoisting">
    Deep dive into how JavaScript hoists declarations
  </Card>
  <Card title="IIFE, Modules and Namespaces" icon="box" href="/concepts/iife-modules">
    Patterns that leverage scope for encapsulation
  </Card>
  <Card title="this, call, apply and bind" icon="bullseye" href="/concepts/this-call-apply-bind">
    Understanding execution context alongside scope
  </Card>
  <Card title="Higher Order Functions" icon="arrows-repeat" href="/concepts/higher-order-functions">
    Functions that return functions often create closures
  </Card>
  <Card title="Currying & Composition" icon="wand-magic-sparkles" href="/concepts/currying-composition">
    Advanced patterns built on closures
  </Card>
</CardGroup>

---

## Reference

<CardGroup cols={2}>
  <Card title="Closures β€” MDN" icon="book" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures">
    Official MDN documentation on closures and lexical scoping
  </Card>
  <Card title="Scope β€” MDN Glossary" icon="book" href="https://developer.mozilla.org/en-US/docs/Glossary/Scope">
    MDN glossary entry explaining scope in JavaScript
  </Card>
  <Card title="var β€” MDN" icon="book" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var">
    Reference for the var keyword, function scope, and hoisting
  </Card>
  <Card title="let β€” MDN" icon="book" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let">
    Reference for the let keyword and block scope
  </Card>
  <Card title="const β€” MDN" icon="book" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const">
    Reference for the const keyword and immutable bindings
  </Card>
  <Card title="Closures β€” JavaScript.Info" icon="book" href="https://javascript.info/closure">
    In-depth tutorial on closures and lexical environment
  </Card>
</CardGroup>

## Books

<Card title="You Don't Know JS Yet: Scope & Closures β€” Kyle Simpson" icon="book" href="https://github.com/getify/You-Dont-Know-JS/tree/2nd-ed/scope-closures">
  The definitive deep-dive into JavaScript scope and closures. Free to read online. This book will transform your understanding of how JavaScript really works.
</Card>

## Articles

<CardGroup cols={2}>
  <Card title="Var, Let, and Const – What's the Difference?" icon="newspaper" href="https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/">
    Clear FreeCodeCamp guide comparing the three variable declaration keywords with practical examples.
  </Card>
  <Card title="JavaScript Scope and Closures" icon="newspaper" href="https://css-tricks.com/javascript-scope-closures/">
    Zell Liew's comprehensive CSS-Tricks article covering both scope and closures in one excellent resource.
  </Card>
  <Card title="whatthefuck.is Β· A Closure" icon="newspaper" href="https://whatthefuck.is/closure">
    Dan Abramov's clear, concise explanation of closures. Perfect for the "aha moment."
  </Card>
  <Card title="I never understood JavaScript closures" icon="newspaper" href="https://medium.com/dailyjs/i-never-understood-javascript-closures-9663703368e8">
    Olivier De Meulder's article that has helped countless developers finally understand closures.
  </Card>
  <Card title="The Difference Between Function and Block Scope" icon="newspaper" href="https://medium.com/@josephcardillo/the-difference-between-function-and-block-scope-in-javascript-4296b2322abe">
    Joseph Cardillo's focused explanation of how var differs from let and const in terms of scope.
  </Card>
  <Card title="Closures: Using Memoization" icon="newspaper" href="https://dev.to/steelvoltage/closures-using-memoization-3597">
    Brian Barbour's practical guide showing how closures enable powerful caching patterns.
  </Card>
</CardGroup>

## Tools

<Card title="JavaScript Tutor β€” Visualize Code Execution" icon="play" href="https://pythontutor.com/javascript.html">
  Step through JavaScript code and see how closures capture variables in real-time. Visualize the scope chain, execution contexts, and how functions "remember" their environment. Perfect for understanding closures visually.
</Card>

## Courses

<Card title="JavaScript: Understanding the Weird Parts (First 3.5 Hours)" icon="graduation-cap" href="https://www.youtube.com/watch?v=Bv_5Zv5c-Ts">
  Free preview of Anthony Alicea's acclaimed course. Excellent coverage of scope, closures, and execution contexts.
</Card>

## Videos

<CardGroup cols={2}>
  <Card title="JavaScript The Hard Parts: Closure, Scope & Execution Context" icon="video" href="https://www.youtube.com/watch?v=XTAzsODSCsM">
    Will Sentance draws out execution contexts and the scope chain on a whiteboard as code runs. This visual approach makes the "how" of closures click.
  </Card>
  <Card title="Closures in JavaScript" icon="video" href="https://youtu.be/qikxEIxsXco">
    Akshay Saini's popular Namaste JavaScript episode with clear visual explanations.
  </Card>
  <Card title="Closures β€” Fun Fun Function" icon="video" href="https://www.youtube.com/watch?v=CQqwU2Ixu-U">
    Mattias Petter Johansson's entertaining and educational take on closures.
  </Card>
  <Card title="Learn Closures In 7 Minutes" icon="video" href="https://www.youtube.com/watch?v=3a0I8ICR1Vg">
    Web Dev Simplified's concise, beginner-friendly closure explanation.
  </Card>
</CardGroup>