WEBVTT

1
00:00:00.120 --> 00:00:04.639
<v Speaker 1>Welcome to the deep dive. Today. We're going deep on

2
00:00:04.759 --> 00:00:10.599
<v Speaker 1>something that seems, I don't know, deceptively simple in JavaScript

3
00:00:10.679 --> 00:00:13.279
<v Speaker 1>variables we use them all the time obviously, but have

4
00:00:13.400 --> 00:00:16.320
<v Speaker 1>you ever stopped to think about like where they actually

5
00:00:16.359 --> 00:00:19.760
<v Speaker 1>live in the code and how the JavaScript engine actually

6
00:00:19.800 --> 00:00:23.399
<v Speaker 1>finds them. You know, That's what scope is all about,

7
00:00:23.480 --> 00:00:26.480
<v Speaker 1>and believe me, it gets way more interesting than you

8
00:00:26.559 --> 00:00:30.239
<v Speaker 1>might think it does. Our guide for this deep dive

9
00:00:30.519 --> 00:00:34.640
<v Speaker 1>is Kyle Simpson's book You Don't Know JS Scope Enclosures.

10
00:00:35.439 --> 00:00:38.719
<v Speaker 1>He really digs deep into like the guts of how

11
00:00:38.799 --> 00:00:42.000
<v Speaker 1>JavaScript works, and we're going to unpack some of the

12
00:00:42.039 --> 00:00:44.520
<v Speaker 1>key insights from his work. Hopefully, you know, make it clear.

13
00:00:44.679 --> 00:00:46.359
<v Speaker 1>By the end of this you'll have a rock solid

14
00:00:46.399 --> 00:00:51.240
<v Speaker 1>understanding of scope and it's close relative closures, which will

15
00:00:51.280 --> 00:00:54.200
<v Speaker 1>make you, I hope, a much more confident JavaScript developer.

16
00:00:54.600 --> 00:00:56.600
<v Speaker 1>Right off the bat, Kyle reveals something that kind of

17
00:00:56.600 --> 00:01:00.039
<v Speaker 1>blew my mind. JavaScript is actually a compiled language. I

18
00:01:00.039 --> 00:01:01.719
<v Speaker 1>always thought it was like interpreted.

19
00:01:02.000 --> 00:01:03.920
<v Speaker 2>I know, it's a common misconception. A lot of people

20
00:01:04.000 --> 00:01:06.959
<v Speaker 2>think that, well, JavaScript isn't compiled ahead of time like

21
00:01:07.000 --> 00:01:09.680
<v Speaker 2>some languages, you know, C plus plus or something. The

22
00:01:09.719 --> 00:01:13.040
<v Speaker 2>engine actually does compile your code right before execution. Okay,

23
00:01:13.079 --> 00:01:18.760
<v Speaker 2>it's incredibly fast, like microseconds, But it does involve like

24
00:01:19.040 --> 00:01:22.439
<v Speaker 2>breaking down the code into tokens, parsing the structure, and

25
00:01:22.439 --> 00:01:25.239
<v Speaker 2>then actually generating the instructions the computer's going to run.

26
00:01:25.359 --> 00:01:28.439
<v Speaker 1>Huh. So it's not just reading the code like line

27
00:01:28.480 --> 00:01:30.879
<v Speaker 1>by line as it goes. No, not at all interesting.

28
00:01:31.079 --> 00:01:34.719
<v Speaker 2>Yeah, this compilation step is really crucial for how JavaScript

29
00:01:34.799 --> 00:01:37.519
<v Speaker 2>handles scope. So think of scope as a set of

30
00:01:37.599 --> 00:01:40.760
<v Speaker 2>rules that determine where variables live and how the code

31
00:01:40.760 --> 00:01:41.560
<v Speaker 2>can access them.

32
00:01:41.640 --> 00:01:45.640
<v Speaker 1>Okay, that makes sense. Kyle uses this idea of LHS

33
00:01:45.680 --> 00:01:48.680
<v Speaker 1>and RHS lookups to explain how this works. Can you

34
00:01:48.680 --> 00:01:49.879
<v Speaker 1>break that down a little bit? Sure.

35
00:01:49.959 --> 00:01:52.599
<v Speaker 2>Imagine the JavaScript engines like having a conversation with a

36
00:01:52.599 --> 00:01:55.079
<v Speaker 2>friend called scope. Okay, So when the engine needs to

37
00:01:55.120 --> 00:01:57.560
<v Speaker 2>assign a value to a variable, like you know, in

38
00:01:57.599 --> 00:02:03.040
<v Speaker 2>a statement like two, it basically asks Scope, Hey, I

39
00:02:03.079 --> 00:02:06.239
<v Speaker 2>need to put this value two tons somewhere. Do you

40
00:02:06.359 --> 00:02:09.840
<v Speaker 2>have a container labeled A Okay, So that's an LHS lookup.

41
00:02:10.120 --> 00:02:11.879
<v Speaker 2>It's looking for the target of the assignment.

42
00:02:11.960 --> 00:02:14.080
<v Speaker 1>So it's like finding the right box to put something

43
00:02:14.120 --> 00:02:14.919
<v Speaker 1>in exactly.

44
00:02:15.039 --> 00:02:17.719
<v Speaker 2>Now, if the code needs to actually read the value

45
00:02:17.759 --> 00:02:21.800
<v Speaker 2>of a variable. Like in console dot log the engine asks, so, hey,

46
00:02:21.800 --> 00:02:23.919
<v Speaker 2>can you tell me what's inside the container labeled A.

47
00:02:24.520 --> 00:02:26.919
<v Speaker 2>That's an RHS lookup. It's retrieving the value.

48
00:02:27.039 --> 00:02:31.719
<v Speaker 1>Got it. So LHS is for assigning, RHS is for retrieving.

49
00:02:32.360 --> 00:02:35.360
<v Speaker 1>But how does this relate to nested scopes, like you

50
00:02:35.400 --> 00:02:37.520
<v Speaker 1>know when you have functions within functions.

51
00:02:37.599 --> 00:02:40.520
<v Speaker 2>Yeah, so think of nested scopes kind of like floors

52
00:02:40.560 --> 00:02:43.400
<v Speaker 2>in a building. Okay, each function creates a new floor.

53
00:02:43.919 --> 00:02:46.560
<v Speaker 2>If the engine can't find a variable on the current floor,

54
00:02:46.879 --> 00:02:49.400
<v Speaker 2>it takes the elevator up to the next level, searching

55
00:02:49.439 --> 00:02:52.400
<v Speaker 2>each enclosing scope until it reaches the top floor, which

56
00:02:52.400 --> 00:02:53.719
<v Speaker 2>is the global scope.

57
00:02:53.439 --> 00:02:56.599
<v Speaker 1>Global scope, and if it can't find the variable even

58
00:02:56.639 --> 00:02:58.000
<v Speaker 1>after going all the way up, then.

59
00:02:57.919 --> 00:03:01.520
<v Speaker 2>You get an error and you get a reference error

60
00:03:02.039 --> 00:03:05.520
<v Speaker 2>for RHS lookups, meaning the variable doesn't exist, and they

61
00:03:05.680 --> 00:03:08.759
<v Speaker 2>type error for LHS lookups if you're trying to assign

62
00:03:08.759 --> 00:03:09.960
<v Speaker 2>to something that can't be assigned to.

63
00:03:10.159 --> 00:03:10.479
<v Speaker 1>Got it?

64
00:03:10.719 --> 00:03:11.000
<v Speaker 2>Yeah?

65
00:03:11.199 --> 00:03:14.719
<v Speaker 1>Okay, so scope is all about where the code can

66
00:03:14.759 --> 00:03:17.800
<v Speaker 1>see the variables. But then what about lexical scope. That

67
00:03:17.840 --> 00:03:20.000
<v Speaker 1>sounds a bit more I don't know, complex.

68
00:03:20.199 --> 00:03:23.520
<v Speaker 2>Yeah, lexical scope just simply means that the scope of

69
00:03:23.599 --> 00:03:26.840
<v Speaker 2>a variable is determined by where it is written in

70
00:03:26.919 --> 00:03:30.960
<v Speaker 2>the code, not by where it's executed. It's like those

71
00:03:31.039 --> 00:03:34.560
<v Speaker 2>Russian nesting dolls. Yeah, each scope is contained within another.

72
00:03:34.360 --> 00:03:36.439
<v Speaker 1>Okay, So if I have a function inside another function,

73
00:03:36.560 --> 00:03:38.759
<v Speaker 1>the inner function can see the variables from the outer

74
00:03:38.759 --> 00:03:39.560
<v Speaker 1>function exactly.

75
00:03:39.680 --> 00:03:43.280
<v Speaker 2>Okay, the interfunction scope is nested within the outer function scope,

76
00:03:43.879 --> 00:03:46.199
<v Speaker 2>and if there's a variable with the same game in

77
00:03:46.240 --> 00:03:52.120
<v Speaker 2>both scopes, the inner function will prioritize its own local variable. Effectively,

78
00:03:52.159 --> 00:03:54.240
<v Speaker 2>it's kind of like shadowing the one from the outer scope.

79
00:03:54.280 --> 00:03:56.240
<v Speaker 1>So lexical scope is all about the structure of the

80
00:03:56.280 --> 00:03:59.280
<v Speaker 1>code itself. Are there ways to break these rules?

81
00:03:59.599 --> 00:04:02.479
<v Speaker 2>Yeah, there are a couple ways to cheat lexical scope,

82
00:04:02.680 --> 00:04:05.000
<v Speaker 2>but they're generally frowned upon because it makes your code

83
00:04:05.039 --> 00:04:09.639
<v Speaker 2>harder to understand and potentially like less performant. One is

84
00:04:09.719 --> 00:04:15.719
<v Speaker 2>using evil, which lets you execute arbitrary code dynamically, potentially

85
00:04:15.840 --> 00:04:17.360
<v Speaker 2>changing the scope at runtime, so.

86
00:04:17.319 --> 00:04:19.839
<v Speaker 1>That throws a wrench into the whole like compile time

87
00:04:19.959 --> 00:04:21.360
<v Speaker 1>scope analysis exactly.

88
00:04:21.639 --> 00:04:25.759
<v Speaker 2>The other way is to mess with lexical scope is

89
00:04:25.920 --> 00:04:29.360
<v Speaker 2>using the with statement. It's less common, but it creates

90
00:04:29.360 --> 00:04:31.720
<v Speaker 2>a new scope from an object, which can lead to

91
00:04:31.800 --> 00:04:35.639
<v Speaker 2>confusion and potentially unintended consequences.

92
00:04:35.079 --> 00:04:36.600
<v Speaker 1>So probably best to avoid those.

93
00:04:36.680 --> 00:04:38.600
<v Speaker 2>If we can, yes stick to the clear rules of

94
00:04:38.639 --> 00:04:41.160
<v Speaker 2>lexico scope, it's going to keep your code more predictable

95
00:04:41.399 --> 00:04:43.040
<v Speaker 2>and help the engine optimize it better.

96
00:04:43.199 --> 00:04:44.920
<v Speaker 1>This is making a lot more sense. But so far

97
00:04:44.959 --> 00:04:48.040
<v Speaker 1>we've only talked about like functions creating scopes. What about

98
00:04:48.079 --> 00:04:51.319
<v Speaker 1>other parts of the code, like loops, conditional statements, those

99
00:04:51.360 --> 00:04:53.120
<v Speaker 1>sorts of things. Do they have their own scopes?

100
00:04:53.439 --> 00:04:56.319
<v Speaker 2>That's a great question. So for a long time, JavaScript

101
00:04:56.360 --> 00:04:58.959
<v Speaker 2>only had what's called function scope, meaning functions were the

102
00:04:59.040 --> 00:05:00.199
<v Speaker 2>main creators of scope.

103
00:05:00.600 --> 00:05:04.240
<v Speaker 3>But with six we now have block scope as well

104
00:05:04.439 --> 00:05:07.000
<v Speaker 3>block scope, so now blocks of code can have their

105
00:05:07.040 --> 00:05:11.399
<v Speaker 3>own little, I don't know, isolated spaces for variables exactly.

106
00:05:11.879 --> 00:05:14.639
<v Speaker 2>It's all about this idea of keeping variables like as

107
00:05:14.680 --> 00:05:17.759
<v Speaker 2>contained as possible, following the principle of least privilege.

108
00:05:17.839 --> 00:05:21.000
<v Speaker 1>That sounds like a good security practice.

109
00:05:21.079 --> 00:05:23.879
<v Speaker 2>It is. It helps prevent accidental reuse of variables and

110
00:05:23.920 --> 00:05:27.680
<v Speaker 2>potential conflicts. Leads to cleaner, more maintainable code.

111
00:05:27.839 --> 00:05:30.160
<v Speaker 1>So how do you create a block scope? Is it

112
00:05:30.240 --> 00:05:31.240
<v Speaker 1>just curly braces?

113
00:05:31.600 --> 00:05:35.519
<v Speaker 2>So not all curly braces create a new scope. Traditionally,

114
00:05:35.639 --> 00:05:38.040
<v Speaker 2>four loops didn't actually have their own block scope, which

115
00:05:38.120 --> 00:05:41.079
<v Speaker 2>led to some interesting behavior. But with ES six we

116
00:05:41.199 --> 00:05:44.920
<v Speaker 2>have the let and constant keywords. They allow us to

117
00:05:44.959 --> 00:05:47.680
<v Speaker 2>declare variables that are specifically scope to the block they're

118
00:05:47.680 --> 00:05:48.199
<v Speaker 2>defined in.

119
00:05:48.439 --> 00:05:51.360
<v Speaker 1>Okay, so if I use let inside of a four loop,

120
00:05:51.399 --> 00:05:53.959
<v Speaker 1>that variable is truly contained within that loop exactly.

121
00:05:54.000 --> 00:05:57.120
<v Speaker 2>It's a much cleaner way to manage variables and prevent

122
00:05:57.160 --> 00:06:00.600
<v Speaker 2>them from like accidentally leaking into other parts to the code.

123
00:06:00.759 --> 00:06:04.319
<v Speaker 2>And const is very similar, except it's for declaring constants

124
00:06:04.439 --> 00:06:05.839
<v Speaker 2>values that shouldn't be reassigned.

125
00:06:06.040 --> 00:06:08.639
<v Speaker 1>I gotcha. This is all making a lot more sense now.

126
00:06:09.839 --> 00:06:11.720
<v Speaker 1>But there's one more thing that's always kind of tripped

127
00:06:11.720 --> 00:06:15.800
<v Speaker 1>me up when it comes to scope hoisting. It's like

128
00:06:16.120 --> 00:06:18.720
<v Speaker 1>variables can like magically move around in the code.

129
00:06:19.000 --> 00:06:21.240
<v Speaker 2>Yeah. Hoisting is another one of those things that kind

130
00:06:21.279 --> 00:06:23.839
<v Speaker 2>of highlights the importance of that compilation step we talked

131
00:06:23.839 --> 00:06:28.160
<v Speaker 2>about ear Yeah, so during compilation, the JavaScript engine actually

132
00:06:28.199 --> 00:06:32.800
<v Speaker 2>processes all the variable and function declarations first before any

133
00:06:32.839 --> 00:06:34.279
<v Speaker 2>other code is executed, so.

134
00:06:34.240 --> 00:06:35.959
<v Speaker 1>It's like they're all moved up to the top of

135
00:06:35.959 --> 00:06:36.519
<v Speaker 1>their scope.

136
00:06:36.759 --> 00:06:39.360
<v Speaker 2>Yeah, that's a good way to visualize it mm, and

137
00:06:40.240 --> 00:06:43.160
<v Speaker 2>it can lead to some unexpected behavior if you're not careful.

138
00:06:43.439 --> 00:06:46.439
<v Speaker 2>For example, you can actually use a variable before it

139
00:06:46.480 --> 00:06:49.240
<v Speaker 2>appears to be declared in the code because the declaration

140
00:06:49.319 --> 00:06:51.279
<v Speaker 2>has already been hoisted during compilation.

141
00:06:52.079 --> 00:06:53.959
<v Speaker 1>So I can use a variable before it's declared.

142
00:06:54.439 --> 00:06:56.240
<v Speaker 2>You can use it in the sense that the engine

143
00:06:56.279 --> 00:06:58.759
<v Speaker 2>knows it exists, but it won't have a value yet.

144
00:06:58.839 --> 00:06:59.079
<v Speaker 1>Okay.

145
00:06:59.120 --> 00:07:02.079
<v Speaker 2>This is where the difference between like declaration and assignment

146
00:07:02.120 --> 00:07:02.519
<v Speaker 2>comes in.

147
00:07:02.759 --> 00:07:05.439
<v Speaker 1>Right, So declaring a variable is just telling the engine

148
00:07:05.480 --> 00:07:08.560
<v Speaker 1>it exists. Assigning of value is when you actually put

149
00:07:08.600 --> 00:07:12.399
<v Speaker 1>something in that container. So hoisting only applies to declarations,

150
00:07:12.439 --> 00:07:13.879
<v Speaker 1>not assignments exactly.

151
00:07:14.000 --> 00:07:16.439
<v Speaker 2>The assignment still happens where you write it in the code,

152
00:07:17.160 --> 00:07:20.120
<v Speaker 2>but the declaration is processed beforehand, which can lead to

153
00:07:20.439 --> 00:07:22.600
<v Speaker 2>like some head scratching moments if you're not aware of it.

154
00:07:22.639 --> 00:07:24.879
<v Speaker 1>That gotcha. Okay, I think I'm starting to wrap my

155
00:07:24.920 --> 00:07:27.639
<v Speaker 1>head around hoisting a little bit. Any other I don't

156
00:07:27.680 --> 00:07:29.319
<v Speaker 1>know quirks I should be aware of.

157
00:07:29.920 --> 00:07:32.519
<v Speaker 2>One kind of interesting thing is that function declarations are

158
00:07:32.560 --> 00:07:36.399
<v Speaker 2>hoisted before variable declarations. So if you have a function

159
00:07:36.480 --> 00:07:39.240
<v Speaker 2>and a variable with the same name, the function declaration

160
00:07:39.319 --> 00:07:42.240
<v Speaker 2>will actually take precedence. But in general, you know, it's

161
00:07:42.240 --> 00:07:45.120
<v Speaker 2>good practice to just avoid these kinds of situations and

162
00:07:45.240 --> 00:07:47.560
<v Speaker 2>write like clear and predictable code.

163
00:07:47.639 --> 00:07:48.959
<v Speaker 1>It sounds like solid advice.

164
00:07:49.279 --> 00:07:49.800
<v Speaker 2>Yeah.

165
00:07:49.920 --> 00:07:54.519
<v Speaker 1>Okay, So we've covered scope, lexical scope, breaking the rules,

166
00:07:54.720 --> 00:07:58.279
<v Speaker 1>block scope, and hoisting. We've gone pretty deep into how

167
00:07:58.360 --> 00:08:02.319
<v Speaker 1>JavaScript handles variables. But there's one more big concept that

168
00:08:02.360 --> 00:08:06.079
<v Speaker 1>always seems like shrouded in mystery. Closures.

169
00:08:07.519 --> 00:08:08.079
<v Speaker 2>Closures.

170
00:08:08.480 --> 00:08:12.399
<v Speaker 1>Yeah, it's often seen as this advanced, almost magical concept

171
00:08:12.480 --> 00:08:15.399
<v Speaker 1>in JavaScript, but it's actually simpler than it sounds. It's

172
00:08:15.399 --> 00:08:17.720
<v Speaker 1>something that just happens naturally in your code all the time.

173
00:08:18.519 --> 00:08:22.639
<v Speaker 2>Really, I've always been like kind of intimidated by closures. Yeah,

174
00:08:22.680 --> 00:08:26.879
<v Speaker 2>what exactly is a closure? And why should I even

175
00:08:26.920 --> 00:08:27.560
<v Speaker 2>care about them?

176
00:08:27.959 --> 00:08:32.159
<v Speaker 1>So a closure is simply a function's ability to remember

177
00:08:32.320 --> 00:08:36.200
<v Speaker 1>and access its lexical scope even when it's executed outside

178
00:08:36.200 --> 00:08:39.279
<v Speaker 1>of that original scope. Okay, it's a natural consequence of

179
00:08:39.279 --> 00:08:40.720
<v Speaker 1>how scope works in JavaScript.

180
00:08:40.840 --> 00:08:42.840
<v Speaker 2>Can you give me an example of that. I'm still

181
00:08:42.879 --> 00:08:44.799
<v Speaker 2>a little hazy on what that actually, you know what

182
00:08:44.840 --> 00:08:45.360
<v Speaker 2>that looks like?

183
00:08:45.480 --> 00:08:49.240
<v Speaker 1>Sure? Imagine you have a function called outer function, and it,

184
00:08:49.360 --> 00:08:52.919
<v Speaker 1>you know, declares a variable called message inside of our function,

185
00:08:52.960 --> 00:08:56.000
<v Speaker 1>you define another function, inner function right now, because of

186
00:08:56.080 --> 00:09:00.000
<v Speaker 1>lexical scope, inner function can access the message variable from out.

187
00:09:00.200 --> 00:09:02.840
<v Speaker 2>Function, right, because you know, the inner function can see.

188
00:09:02.639 --> 00:09:05.759
<v Speaker 1>Those variables exactly. But here's the interesting part. If outer

189
00:09:05.840 --> 00:09:08.639
<v Speaker 1>function returns inner function like gives it back to the

190
00:09:08.679 --> 00:09:09.679
<v Speaker 1>outside world.

191
00:09:09.600 --> 00:09:13.240
<v Speaker 2>Right, and we later execute inner function, it can still

192
00:09:13.279 --> 00:09:16.480
<v Speaker 2>access that message variable even though outer function is finished running.

193
00:09:16.639 --> 00:09:19.679
<v Speaker 1>Wait, so interfunction is holding onto that scope even after

194
00:09:19.759 --> 00:09:21.600
<v Speaker 1>outer function is done exactly.

195
00:09:21.679 --> 00:09:26.200
<v Speaker 2>That's closure in action. Interfunction is closed over the scope

196
00:09:26.200 --> 00:09:29.240
<v Speaker 2>of outer function, preserving its access to the variables in

197
00:09:29.240 --> 00:09:29.759
<v Speaker 2>that scope.

198
00:09:30.000 --> 00:09:30.600
<v Speaker 3>Wow.

199
00:09:30.639 --> 00:09:34.000
<v Speaker 2>And this is incredibly powerful because it allows functions to

200
00:09:35.159 --> 00:09:38.159
<v Speaker 2>maintain their own private state even as they're passed around

201
00:09:38.159 --> 00:09:39.919
<v Speaker 2>and executed in different parts of the code.

202
00:09:40.080 --> 00:09:43.159
<v Speaker 1>Okay, I'm starting to see why closures are a big deal.

203
00:09:43.679 --> 00:09:46.799
<v Speaker 1>But where do we actually encounter them in real world code? Like,

204
00:09:46.919 --> 00:09:50.039
<v Speaker 1>is this just a theoretical concept or are closures actually

205
00:09:50.080 --> 00:09:51.840
<v Speaker 1>doing useful stuff behind the scenes.

206
00:09:52.399 --> 00:09:57.679
<v Speaker 2>Closures are incredibly common. They're at work whenever you use callbacks, timers,

207
00:09:57.799 --> 00:10:01.440
<v Speaker 2>event handlers, pretty much anything synchronous in JavaScript.

208
00:10:01.519 --> 00:10:02.039
<v Speaker 1>Oh okay.

209
00:10:02.080 --> 00:10:04.279
<v Speaker 2>For example, when you pass a function to set time out,

210
00:10:04.600 --> 00:10:07.159
<v Speaker 2>that function is going to be executed later, long after

211
00:10:07.200 --> 00:10:10.200
<v Speaker 2>the code that define its finished running, but thanks to closure,

212
00:10:10.679 --> 00:10:13.120
<v Speaker 2>it still has access to the variables it needs from

213
00:10:13.120 --> 00:10:14.159
<v Speaker 2>its original scope.

214
00:10:14.279 --> 00:10:16.960
<v Speaker 1>So closures are like a time machine for scope. They

215
00:10:17.000 --> 00:10:20.320
<v Speaker 1>allow functions to like travel through time and you know,

216
00:10:20.360 --> 00:10:21.759
<v Speaker 1>carry their context with them.

217
00:10:21.919 --> 00:10:23.720
<v Speaker 2>That's a great way to put it. Wow. Yeah, it's

218
00:10:23.759 --> 00:10:26.360
<v Speaker 2>one of the things that makes JavaScript so flexible and powerful.

219
00:10:26.559 --> 00:10:29.720
<v Speaker 1>Okay, I'm starting to like see the light here. Yeah,

220
00:10:29.759 --> 00:10:33.440
<v Speaker 1>but there's one particular scenario involving closures that always kind

221
00:10:33.440 --> 00:10:37.200
<v Speaker 1>of baffled me. Closures and loops. Yeah, I've run into

222
00:10:37.200 --> 00:10:40.399
<v Speaker 1>some like unexpected behavior when combining those two.

223
00:10:40.480 --> 00:10:43.559
<v Speaker 2>Closures and loops can definitely be tricky. Yeah, it's a

224
00:10:43.559 --> 00:10:47.960
<v Speaker 2>classic case where our intuition might not match like how

225
00:10:48.039 --> 00:10:52.639
<v Speaker 2>JavaScript actually works. Let's delve into that next time, explore

226
00:10:52.679 --> 00:10:55.919
<v Speaker 2>why it can be so confusing, and more importantly, how

227
00:10:55.919 --> 00:10:56.879
<v Speaker 2>to handle it effectively.

228
00:10:57.039 --> 00:11:00.559
<v Speaker 1>Yeah, let's do it. Welcome back to the deep dive.

229
00:11:01.720 --> 00:11:05.080
<v Speaker 1>Last time we kind of dove into that fascinating world

230
00:11:05.159 --> 00:11:08.320
<v Speaker 1>of JavaScript scope enclosures, we even you know, started to

231
00:11:08.440 --> 00:11:12.200
<v Speaker 1>unravel some of those mysteries surrounding them. Today we're going

232
00:11:12.279 --> 00:11:16.320
<v Speaker 1>to tackle I think one of the trickiest scenarios involving closures,

233
00:11:16.840 --> 00:11:20.879
<v Speaker 1>closures within loops. I've run into like some head scratching

234
00:11:20.879 --> 00:11:22.840
<v Speaker 1>moments with this before. Yeah, and I'm sure you know

235
00:11:22.879 --> 00:11:24.840
<v Speaker 1>a lot of other JavaScript developers have too.

236
00:11:24.960 --> 00:11:27.840
<v Speaker 2>Oh yeah, absolutely, it can definitely be a bit of

237
00:11:27.840 --> 00:11:30.000
<v Speaker 2>a minefield. You to be careful with those. Yeah, it's

238
00:11:30.039 --> 00:11:33.320
<v Speaker 2>one of those places where, like the asynchronous nature of

239
00:11:33.399 --> 00:11:37.720
<v Speaker 2>JavaScript can really throw you for a loop. It's it

240
00:11:37.759 --> 00:11:40.000
<v Speaker 2>often trips up even experienced developers.

241
00:11:40.120 --> 00:11:43.399
<v Speaker 1>Okay, so let's kind of set the stage here. What's

242
00:11:43.519 --> 00:11:49.600
<v Speaker 1>the typical scenario where closures and loops like collide?

243
00:11:50.120 --> 00:11:52.159
<v Speaker 2>So one really common one is when you're trying to

244
00:11:52.200 --> 00:11:55.879
<v Speaker 2>set up a series of delayed actions using set time

245
00:11:55.879 --> 00:11:58.559
<v Speaker 2>out within a loop, Okay, where each timeout is supposed

246
00:11:58.559 --> 00:11:59.879
<v Speaker 2>to like reference the loop counter.

247
00:12:00.159 --> 00:12:00.279
<v Speaker 1>Right.

248
00:12:00.480 --> 00:12:04.039
<v Speaker 2>It seems really straightforward at first, but the results can

249
00:12:04.080 --> 00:12:05.000
<v Speaker 2>be kind of surprising.

250
00:12:05.120 --> 00:12:07.519
<v Speaker 1>I think I've been there. You Like, you expect each

251
00:12:07.600 --> 00:12:10.399
<v Speaker 1>time out to capture the current value of the loop counter,

252
00:12:10.720 --> 00:12:12.720
<v Speaker 1>but things don't quite work out the way you think

253
00:12:12.720 --> 00:12:15.080
<v Speaker 1>they're going to. Can you can you give us an

254
00:12:15.120 --> 00:12:16.360
<v Speaker 1>example like walk us through that?

255
00:12:16.519 --> 00:12:19.480
<v Speaker 2>Sure? Sure, So let's say we have a loop that

256
00:12:19.639 --> 00:12:22.919
<v Speaker 2>iterates you know from one to five, okay, and within

257
00:12:23.080 --> 00:12:28.240
<v Speaker 2>each iteration we set a time out that logs the

258
00:12:28.440 --> 00:12:31.080
<v Speaker 2>current value of the loop counter after you know, one

259
00:12:31.120 --> 00:12:34.039
<v Speaker 2>second delay. The code might look, you know, something like this.

260
00:12:34.440 --> 00:12:39.399
<v Speaker 2>So we've got for barkyei one I expense five I

261
00:12:39.480 --> 00:12:43.600
<v Speaker 2>plus plus set time out function I one thousand.

262
00:12:43.639 --> 00:12:45.919
<v Speaker 1>Okay, similar enough. I have a feeling it's not going

263
00:12:46.000 --> 00:12:47.039
<v Speaker 1>to do what we expect though.

264
00:12:47.200 --> 00:12:49.159
<v Speaker 2>Yeah, you're right to be suspicious.

265
00:12:49.240 --> 00:12:49.399
<v Speaker 1>Yea.

266
00:12:49.639 --> 00:12:51.759
<v Speaker 2>If you actually run this code, you'll see it logs

267
00:12:51.759 --> 00:12:55.120
<v Speaker 2>the number six five times, all after the loop's completed.

268
00:12:55.200 --> 00:12:58.639
<v Speaker 1>Wait a minute, six, But the loop only goes to five, right,

269
00:12:58.720 --> 00:13:00.960
<v Speaker 1>and why is it logging it like five times? What's

270
00:13:01.000 --> 00:13:01.600
<v Speaker 1>going on there?

271
00:13:01.840 --> 00:13:03.799
<v Speaker 2>It all kind of boils down to that combination of

272
00:13:03.840 --> 00:13:07.799
<v Speaker 2>scope closures and the asynchronous nature of set timeout. When

273
00:13:07.799 --> 00:13:10.799
<v Speaker 2>we create those timeout functions within the loop, they each

274
00:13:10.840 --> 00:13:13.639
<v Speaker 2>form a closure capturing a reference to the variable eye

275
00:13:13.679 --> 00:13:14.720
<v Speaker 2>from the surrounding scope.

276
00:13:14.840 --> 00:13:17.240
<v Speaker 1>Okay, so they have a like connection back to that

277
00:13:17.399 --> 00:13:18.799
<v Speaker 1>to that variable.

278
00:13:18.440 --> 00:13:22.559
<v Speaker 2>Yeah, exactly. However, those timeout functions don't execute right.

279
00:13:22.480 --> 00:13:23.559
<v Speaker 1>Away right they're delayed.

280
00:13:23.600 --> 00:13:26.039
<v Speaker 2>They're scheduled to run after a delay, and by the

281
00:13:26.039 --> 00:13:28.600
<v Speaker 2>time they actually get around to executing the loop is

282
00:13:28.639 --> 00:13:31.120
<v Speaker 2>already finished, and the value of eye has reached six.

283
00:13:31.440 --> 00:13:33.440
<v Speaker 1>So they're all looking at the same eye, which has

284
00:13:33.480 --> 00:13:36.320
<v Speaker 1>been incremented beyond the loop, like the range of the

285
00:13:36.360 --> 00:13:40.000
<v Speaker 1>loop exactly. But why does it log six five times?

286
00:13:40.000 --> 00:13:42.519
<v Speaker 1>Why wouldn't it just log it once at the very

287
00:13:42.600 --> 00:13:43.759
<v Speaker 1>end when the loop's done.

288
00:13:44.279 --> 00:13:48.200
<v Speaker 2>So we see six five times because we created five

289
00:13:48.240 --> 00:13:51.480
<v Speaker 2>timeout functions, each one with its own closure over the

290
00:13:51.519 --> 00:13:52.360
<v Speaker 2>same eye variable.

291
00:13:52.440 --> 00:13:52.759
<v Speaker 1>Got it.

292
00:13:52.799 --> 00:13:56.519
<v Speaker 2>They all essentially have this shared memory of that variable,

293
00:13:56.919 --> 00:13:59.159
<v Speaker 2>and they all see its final value when they finally

294
00:13:59.159 --> 00:13:59.559
<v Speaker 2>do run.

295
00:14:00.000 --> 00:14:02.360
<v Speaker 1>Okay, it's like they have a delayed reaction, but by

296
00:14:02.399 --> 00:14:05.120
<v Speaker 1>the time they react, the world has changed and the

297
00:14:05.200 --> 00:14:07.120
<v Speaker 1>value of I is no longer what they thought it

298
00:14:07.200 --> 00:14:07.639
<v Speaker 1>was going to be.

299
00:14:07.799 --> 00:14:10.399
<v Speaker 2>That's a great analogy. So the question is, how do

300
00:14:10.440 --> 00:14:13.960
<v Speaker 2>we fix this? How do we make each timeout capture

301
00:14:13.960 --> 00:14:16.360
<v Speaker 2>the right value of I at the time it was defined.

302
00:14:16.639 --> 00:14:19.480
<v Speaker 1>H that's a good question. I mean we need, I

303
00:14:19.480 --> 00:14:24.519
<v Speaker 1>guess a way to like isolate each timeout scrip so

304
00:14:24.559 --> 00:14:27.440
<v Speaker 1>that it has its own kind of private copy of

305
00:14:27.480 --> 00:14:29.840
<v Speaker 1>the loop counter. And I remember you mentioned last time

306
00:14:30.559 --> 00:14:35.080
<v Speaker 1>aie s those like immediately invoked function expressions.

307
00:14:35.159 --> 00:14:38.879
<v Speaker 2>Yeah, you're on the right track iifes are a classic

308
00:14:38.919 --> 00:14:39.840
<v Speaker 2>solution to this problem.

309
00:14:39.960 --> 00:14:40.240
<v Speaker 1>Okay.

310
00:14:40.600 --> 00:14:43.720
<v Speaker 2>By wrapping that code inside the loop in an IEF,

311
00:14:44.519 --> 00:14:46.799
<v Speaker 2>we can create a new scope for each iteration. So

312
00:14:46.879 --> 00:14:48.960
<v Speaker 2>it looks something like this we've got for our I

313
00:14:49.080 --> 00:14:53.600
<v Speaker 2>one I will five I plus plus set timeout functionconsole

314
00:14:53.639 --> 00:14:54.559
<v Speaker 2>dot log I.

315
00:14:54.879 --> 00:14:57.759
<v Speaker 1>Okay, so we're creating like a self executing function with

316
00:14:57.799 --> 00:15:00.360
<v Speaker 1>in each iteration of the loop and passing in the

317
00:15:00.399 --> 00:15:02.799
<v Speaker 1>current value of I into it. And I see we're

318
00:15:02.799 --> 00:15:06.399
<v Speaker 1>also using like a different variable name J inside the IQ.

319
00:15:06.559 --> 00:15:07.000
<v Speaker 1>What's that for?

320
00:15:07.320 --> 00:15:09.840
<v Speaker 2>Yeah, so that J variable inside the IQ. It creates

321
00:15:09.840 --> 00:15:13.000
<v Speaker 2>a new, like distinct variable within the ip zone scope. Okay,

322
00:15:13.399 --> 00:15:15.799
<v Speaker 2>And that ensures that each timeout function has its own

323
00:15:16.120 --> 00:15:19.000
<v Speaker 2>like private copy of the loop counter, got it, effectively

324
00:15:19.039 --> 00:15:20.559
<v Speaker 2>isolating it from the outer loop's eye.

325
00:15:20.799 --> 00:15:23.039
<v Speaker 1>Right. Okay, so we're kind of creating like these little

326
00:15:23.080 --> 00:15:24.840
<v Speaker 1>isolated scope bubbles exactly.

327
00:15:24.879 --> 00:15:29.440
<v Speaker 2>That prevents those those timing conflicts. And you might remember

328
00:15:29.440 --> 00:15:31.679
<v Speaker 2>from last time E six and introduced an even more

329
00:15:31.679 --> 00:15:36.000
<v Speaker 2>elegant solution for this using the let keyword. Oh, let

330
00:15:36.440 --> 00:15:39.840
<v Speaker 2>creates block scoped variables, right, So when you use let

331
00:15:39.919 --> 00:15:42.879
<v Speaker 2>in the loop heeader, it effectively creates a new binding

332
00:15:43.200 --> 00:15:44.440
<v Speaker 2>for that loop counter on.

333
00:15:44.399 --> 00:15:47.440
<v Speaker 1>Each iteration, so we can actually just like simplify that

334
00:15:47.519 --> 00:15:50.399
<v Speaker 1>code even further. We don't even need that if exactly.

335
00:15:50.559 --> 00:15:50.759
<v Speaker 3>Wow.

336
00:15:51.000 --> 00:15:53.120
<v Speaker 2>So the E S six version using let would look

337
00:15:53.200 --> 00:15:57.679
<v Speaker 2>like this for let I one, I five, I plus plus. Yeah,

338
00:15:57.840 --> 00:16:00.000
<v Speaker 2>set time out, function building much clean.

339
00:16:00.440 --> 00:16:03.480
<v Speaker 1>Yeah. Wow, the let keyword just takes care of all

340
00:16:03.480 --> 00:16:06.960
<v Speaker 1>that for us. Yeah, this block soaping stuff is pretty powerful.

341
00:16:07.039 --> 00:16:07.320
<v Speaker 2>It is.

342
00:16:07.399 --> 00:16:10.399
<v Speaker 1>So we've seen how closures within loops can kind of

343
00:16:10.480 --> 00:16:13.039
<v Speaker 1>lead to this unexpected behavior, but we've also learned and

344
00:16:13.159 --> 00:16:16.480
<v Speaker 1>how to kind of tame them using II fees or

345
00:16:16.919 --> 00:16:19.879
<v Speaker 1>you know, that let keyword. Now, I can't help but

346
00:16:19.919 --> 00:16:22.480
<v Speaker 1>wonder if these same kind of scenarios like pop up

347
00:16:22.480 --> 00:16:25.279
<v Speaker 1>in other areas of JavaScript, especially when we're dealing with like,

348
00:16:25.600 --> 00:16:29.840
<v Speaker 1>you know, asynchronous operations like ajax requests, those sorts of things.

349
00:16:29.879 --> 00:16:33.000
<v Speaker 2>Yeah, that's a great observation. Closures in asynchronous operations like

350
00:16:33.039 --> 00:16:35.600
<v Speaker 2>go hand in hand, right, and those timing intricacies that

351
00:16:35.600 --> 00:16:39.639
<v Speaker 2>we've been talking about, they can lead to similar similar challenges. Right,

352
00:16:39.720 --> 00:16:42.480
<v Speaker 2>So let's let's explore that a little bit further and

353
00:16:42.960 --> 00:16:45.480
<v Speaker 2>see how these same principles and solutions that we've talked

354
00:16:45.519 --> 00:16:46.799
<v Speaker 2>about applying those scenarios.

355
00:16:47.720 --> 00:16:52.000
<v Speaker 1>Welcome back to the deep dive. We've we've really explored

356
00:16:52.080 --> 00:16:57.240
<v Speaker 1>this like intricate dance between scope enclosures in JavaScript and

357
00:16:57.320 --> 00:17:01.000
<v Speaker 1>even tackled that tricky terrain of closures within loops. Now

358
00:17:01.039 --> 00:17:03.960
<v Speaker 1>it's time to bring it all together. See how these

359
00:17:04.000 --> 00:17:08.240
<v Speaker 1>closures actually underpin one of the most powerful patterns in JavaScript,

360
00:17:08.279 --> 00:17:09.440
<v Speaker 1>the module pattern.

361
00:17:09.920 --> 00:17:14.240
<v Speaker 2>Module pattern, Right, it's all about creating like organized, reusable

362
00:17:14.720 --> 00:17:18.319
<v Speaker 2>units of code that have their own kind of internal

363
00:17:18.359 --> 00:17:22.359
<v Speaker 2>workings and a clear interface for interacting with the outside world.

364
00:17:22.519 --> 00:17:25.319
<v Speaker 1>Yeah. Yeah, it's like building those self contained components, right

365
00:17:25.319 --> 00:17:27.400
<v Speaker 1>that we can just plug and play into different parts

366
00:17:27.400 --> 00:17:33.119
<v Speaker 1>of our application. But how do closures actually enable us

367
00:17:33.160 --> 00:17:34.519
<v Speaker 1>to create these modules?

368
00:17:34.680 --> 00:17:38.079
<v Speaker 2>So, closures are really the key to creating private data

369
00:17:38.079 --> 00:17:41.079
<v Speaker 2>and functionality within a module. Okay, Remember how they allow

370
00:17:41.160 --> 00:17:44.680
<v Speaker 2>functions to hold onto their lexical scope even when they're

371
00:17:44.720 --> 00:17:47.759
<v Speaker 2>executed outside of that scope. Right, we can leverage that

372
00:17:47.880 --> 00:17:51.119
<v Speaker 2>to create like a private compartment within our modules.

373
00:17:51.440 --> 00:17:53.559
<v Speaker 1>Okay, I'm starting to see the connection here. Can you

374
00:17:53.559 --> 00:17:55.920
<v Speaker 1>give us like a concrete example walk us through that.

375
00:17:56.000 --> 00:18:00.400
<v Speaker 2>Sure, let's imagine we're building a simple countermodule. Okay, keep

376
00:18:00.720 --> 00:18:04.559
<v Speaker 2>the actual counter value hidden you know, from the outside world,

377
00:18:04.880 --> 00:18:08.200
<v Speaker 2>allow external code to only interact with it through specific

378
00:18:08.240 --> 00:18:12.319
<v Speaker 2>methods like increment, decrement and get value.

379
00:18:12.559 --> 00:18:16.039
<v Speaker 1>Right right, So we're like creating a controlled environment where

380
00:18:16.079 --> 00:18:19.799
<v Speaker 1>the counter is kind of protected from you know, accidental

381
00:18:19.839 --> 00:18:21.400
<v Speaker 1>manipulation or something exactly.

382
00:18:21.480 --> 00:18:24.160
<v Speaker 2>So here's how we can achieve that using the module pattern.

383
00:18:24.240 --> 00:18:28.000
<v Speaker 2>So we've got vur countermodule function for account increment dot

384
00:18:28.039 --> 00:18:31.039
<v Speaker 2>function for account in function return count, but directly value

385
00:18:31.119 --> 00:18:33.279
<v Speaker 2>dot function get value dot function.

386
00:18:33.680 --> 00:18:37.880
<v Speaker 1>Okay, so we're defining a function called counter module and

387
00:18:37.920 --> 00:18:40.480
<v Speaker 1>then immediately invoking it. What's the purpose of that?

388
00:18:40.720 --> 00:18:44.480
<v Speaker 2>Yeah, so that's uh, that's the essence of an immediately

389
00:18:44.480 --> 00:18:48.519
<v Speaker 2>invoked function expression or ioev. By wrapping our module code

390
00:18:48.559 --> 00:18:53.039
<v Speaker 2>in an IF, we create this new scope that's isolated

391
00:18:53.039 --> 00:18:54.440
<v Speaker 2>from the global scope, got it.

392
00:18:54.480 --> 00:18:56.720
<v Speaker 1>So we're creating that like private compartment you were talking

393
00:18:56.759 --> 00:18:57.599
<v Speaker 1>about exactly.

394
00:18:57.759 --> 00:19:00.680
<v Speaker 2>Now, Notice how we have a variable count inside of

395
00:19:00.680 --> 00:19:05.160
<v Speaker 2>the IF. That variable is only accessible within the scope

396
00:19:05.160 --> 00:19:08.079
<v Speaker 2>of that IA, making it private to our module.

397
00:19:08.359 --> 00:19:11.519
<v Speaker 1>And I see we're returning an object from the IF.

398
00:19:11.680 --> 00:19:13.680
<v Speaker 1>Is that our public api exactly?

399
00:19:14.079 --> 00:19:17.359
<v Speaker 2>That returned object contains the methods that we actually want

400
00:19:17.440 --> 00:19:21.599
<v Speaker 2>to expose to the outside world increment, decrement, and get value.

401
00:19:21.680 --> 00:19:24.759
<v Speaker 1>So external code can call those methods, but it can't

402
00:19:25.440 --> 00:19:28.440
<v Speaker 1>directly mess with the count variable itself exactly.

403
00:19:28.640 --> 00:19:32.119
<v Speaker 2>And here's where closures come in. Okay, those methods, because

404
00:19:32.160 --> 00:19:35.920
<v Speaker 2>they were defined within the IF, they form closures over

405
00:19:35.960 --> 00:19:37.279
<v Speaker 2>the if scope, so.

406
00:19:37.200 --> 00:19:40.160
<v Speaker 1>They have a memory of that internal scope even after

407
00:19:40.200 --> 00:19:41.720
<v Speaker 1>the IFE has finished executing.

408
00:19:41.799 --> 00:19:45.880
<v Speaker 2>Precisely, that's how they can still interact with the private

409
00:19:45.920 --> 00:19:49.279
<v Speaker 2>count variable even though it's not directly accessible from the outside.

410
00:19:49.359 --> 00:19:52.880
<v Speaker 1>This is so clever. So by leverage enclosures, we've created

411
00:19:52.880 --> 00:19:56.960
<v Speaker 1>this like secure encapsulated module with its own internal state

412
00:19:57.000 --> 00:19:58.359
<v Speaker 1>and controlled access.

413
00:19:58.440 --> 00:20:02.519
<v Speaker 2>It's incredibly powerful. It's the foundation of many popular JavaScript

414
00:20:02.640 --> 00:20:03.759
<v Speaker 2>libraries and frameworks.

415
00:20:03.839 --> 00:20:06.359
<v Speaker 1>Now, I remember you mentioned that ES six introduced native

416
00:20:06.359 --> 00:20:08.640
<v Speaker 1>support for modules. Does that make it this kind of

417
00:20:08.640 --> 00:20:11.839
<v Speaker 1>traditional module pattern obsolete.

418
00:20:12.200 --> 00:20:15.440
<v Speaker 2>ES six modules definitely provide a more modern and streamlined

419
00:20:15.480 --> 00:20:20.279
<v Speaker 2>way to work with modules, but that traditional pattern is

420
00:20:20.319 --> 00:20:24.000
<v Speaker 2>still relevant. I think it's valuable to understand the underlying principles,

421
00:20:24.519 --> 00:20:26.799
<v Speaker 2>and it can still be useful in certain situations, especially

422
00:20:26.839 --> 00:20:28.880
<v Speaker 2>if you're working with older codebases.

423
00:20:29.039 --> 00:20:31.200
<v Speaker 1>Right, It's like understanding the roots of a tree even

424
00:20:31.240 --> 00:20:34.039
<v Speaker 1>as it's growing new branches exactly. So what are like,

425
00:20:34.119 --> 00:20:38.039
<v Speaker 1>what are the main differences between ES six modules and

426
00:20:38.079 --> 00:20:39.880
<v Speaker 1>this kind of more traditional pattern.

427
00:20:40.599 --> 00:20:46.400
<v Speaker 2>So ES six modules use explicit important export statements to

428
00:20:46.480 --> 00:20:49.720
<v Speaker 2>actually define the module's interface and how it interacts with

429
00:20:49.759 --> 00:20:53.480
<v Speaker 2>other modules. Got it. So it's a more declarative approach.

430
00:20:53.519 --> 00:20:55.680
<v Speaker 2>It's like build into the language itself.

431
00:20:55.480 --> 00:20:58.359
<v Speaker 1>Right, So instead of relying on IF's andclosures to create

432
00:20:58.359 --> 00:21:02.160
<v Speaker 1>that encapsulation, now we have like dedicated syntax.

433
00:21:01.680 --> 00:21:04.200
<v Speaker 2>For it exactly. And it comes with some advantages. You know.

434
00:21:04.279 --> 00:21:08.359
<v Speaker 2>E six modules are statically analyzable, okay, meaning the module

435
00:21:08.400 --> 00:21:11.279
<v Speaker 2>structure is determined at compile time, which can lead to

436
00:21:11.319 --> 00:21:16.599
<v Speaker 2>performance benefits. They're also more aligned with modern javascripts development practices.

437
00:21:16.599 --> 00:21:20.240
<v Speaker 2>It just makes the code easier to read, reason about,

438
00:21:20.319 --> 00:21:20.920
<v Speaker 2>and maintain.

439
00:21:21.279 --> 00:21:24.160
<v Speaker 1>Cool. So it's definitely the way to go for new projects.

440
00:21:24.400 --> 00:21:27.200
<v Speaker 1>But it's also great to have that understanding of the

441
00:21:27.240 --> 00:21:30.319
<v Speaker 1>traditional module pattern in our back pocket.

442
00:21:30.400 --> 00:21:33.359
<v Speaker 2>Yeah. Absolutely, I think it helps you appreciate the evolution

443
00:21:33.920 --> 00:21:37.440
<v Speaker 2>of JavaScript and the clever techniques people have used to

444
00:21:37.680 --> 00:21:41.839
<v Speaker 2>overcome challenges and build you know, more robust applications.

445
00:21:42.440 --> 00:21:44.319
<v Speaker 1>Well, we've covered a lot of ground in this deep

446
00:21:44.359 --> 00:21:48.119
<v Speaker 1>dive into JavaScript scope and closures, from understanding like the

447
00:21:48.200 --> 00:21:51.759
<v Speaker 1>basic rules of variable access to seeing how closures can

448
00:21:51.799 --> 00:21:56.160
<v Speaker 1>actually empower us to create this modular, maintainable code. It's

449
00:21:56.960 --> 00:21:58.880
<v Speaker 1>it's been a really enlightening journey, I think.

450
00:21:59.039 --> 00:22:02.240
<v Speaker 2>Yeah, I'm glad you found it valuable. Remember these concepts,

451
00:22:02.319 --> 00:22:04.359
<v Speaker 2>they might seem a little bit abstract at first, but

452
00:22:04.400 --> 00:22:08.680
<v Speaker 2>they're like fundamental to mastering JavaScript and writing you know,

453
00:22:08.759 --> 00:22:12.599
<v Speaker 2>truly elegant and powerful code. Keep exploring, keep experimenting, and

454
00:22:12.680 --> 00:22:14.799
<v Speaker 2>keep pushing the boundaries of your JavaScript knowledge.

455
00:22:14.839 --> 00:22:16.799
<v Speaker 1>Awesome. Well, thanks for joining us on the deep dive,

456
00:22:17.200 --> 00:22:19.599
<v Speaker 1>and until next time, happy coding.
