WEBVTT

1
00:00:01.530 --> 00:00:03.490
<v Jonas>The next topic we need to talk about</v>

2
00:00:03.490 --> 00:00:07.570
is a very misunderstood concept in JavaScript

3
00:00:07.570 --> 00:00:09.313
and that is hoisting.

4
00:00:11.550 --> 00:00:14.380
So we learned that an execution context

5
00:00:14.380 --> 00:00:16.810
always contains three parts.

6
00:00:16.810 --> 00:00:18.800
A variable environment,

7
00:00:18.800 --> 00:00:21.530
the scope chain in the current context,

8
00:00:21.530 --> 00:00:23.500
and the disk keyword.

9
00:00:23.500 --> 00:00:26.110
We already learned about the scope chain

10
00:00:26.110 --> 00:00:28.800
and so now it's time to take a closer look

11
00:00:28.800 --> 00:00:31.090
at the variable environment

12
00:00:31.090 --> 00:00:33.750
and in particular at how variables

13
00:00:33.750 --> 00:00:37.320
are actually created in JavaScript.

14
00:00:37.320 --> 00:00:38.810
So in JavaScript

15
00:00:38.810 --> 00:00:41.630
we have a mechanism called hoisting.

16
00:00:41.630 --> 00:00:43.600
And hoisting basically make

17
00:00:43.600 --> 00:00:46.450
some types of variables accessible,

18
00:00:46.450 --> 00:00:49.570
or let's say usable in the code

19
00:00:49.570 --> 00:00:52.963
before they are actually declared in the code.

20
00:00:53.830 --> 00:00:56.520
Now, many people simply define hoisting

21
00:00:56.520 --> 00:01:00.030
by saying that variables are magically lifted

22
00:01:00.030 --> 00:01:03.530
or moved to the top of their scope

23
00:01:03.530 --> 00:01:06.640
for example, to the top of a function.

24
00:01:06.640 --> 00:01:08.790
And that is actually what hoisting

25
00:01:08.790 --> 00:01:11.020
looks like on the surface.

26
00:01:11.020 --> 00:01:12.520
But behind the scenes

27
00:01:12.520 --> 00:01:15.830
that's in fact not what happens.

28
00:01:15.830 --> 00:01:17.970
Instead, behind the scenes

29
00:01:17.970 --> 00:01:19.780
the code is basically scanned

30
00:01:19.780 --> 00:01:24.420
for variable declarations before it is executed.

31
00:01:24.420 --> 00:01:26.430
So this happens during the so-called

32
00:01:26.430 --> 00:01:29.660
creation phase of the execution context

33
00:01:29.660 --> 00:01:32.010
that we talked about before.

34
00:01:32.010 --> 00:01:35.530
Then for each variable that is found in the code,

35
00:01:35.530 --> 00:01:37.630
a new property is created

36
00:01:37.630 --> 00:01:40.330
in a variable environment object.

37
00:01:40.330 --> 00:01:43.470
And that's how hoisting really works.

38
00:01:43.470 --> 00:01:46.150
Now, hoisting does not work the same

39
00:01:46.150 --> 00:01:48.160
for all variable types.

40
00:01:48.160 --> 00:01:50.890
And so let's analyze the way hosting works

41
00:01:50.890 --> 00:01:53.100
for function declarations,

42
00:01:53.100 --> 00:01:55.620
variables defined with var

43
00:01:55.620 --> 00:01:58.670
variables defined with let or const

44
00:01:58.670 --> 00:02:00.700
and function expressions,

45
00:02:00.700 --> 00:02:03.410
and also arrow functions.

46
00:02:03.410 --> 00:02:07.060
So function declarations are actually hoisted

47
00:02:07.060 --> 00:02:10.360
and the initial value in the variable environment

48
00:02:10.360 --> 00:02:13.550
is set to the actual function.

49
00:02:13.550 --> 00:02:15.970
So in practice, what this means

50
00:02:15.970 --> 00:02:18.490
is that we can use function declarations

51
00:02:18.490 --> 00:02:22.430
before they are actually declared in the code,

52
00:02:22.430 --> 00:02:24.340
again, because they are stored

53
00:02:24.340 --> 00:02:26.650
in the variable environment object,

54
00:02:26.650 --> 00:02:30.360
even before the code starts executing.

55
00:02:30.360 --> 00:02:32.070
And I actually told you before

56
00:02:32.070 --> 00:02:35.030
that function declarations work this way,

57
00:02:35.030 --> 00:02:37.290
but now you understand why.

58
00:02:37.290 --> 00:02:39.900
It is because of hoisting.

59
00:02:39.900 --> 00:02:43.100
And just to make this table a bit more complete

60
00:02:43.100 --> 00:02:46.450
so that it serves as a nice overview for you,

61
00:02:46.450 --> 00:02:49.280
I also show here that function declarations

62
00:02:49.280 --> 00:02:52.800
are block scoped as we learned before.

63
00:02:52.800 --> 00:02:55.360
Just keep in mind that this is only true

64
00:02:55.360 --> 00:02:57.220
for strict mode.

65
00:02:57.220 --> 00:02:59.430
So if you're using a sloppy mode,

66
00:02:59.430 --> 00:03:00.800
which you shouldn't ,

67
00:03:00.800 --> 00:03:04.070
then functions are functioned sculpt.

68
00:03:04.070 --> 00:03:07.310
Next, variables declared with var

69
00:03:07.310 --> 00:03:10.370
are also hoisted, but hoisting works

70
00:03:10.370 --> 00:03:12.430
in a different way here.

71
00:03:12.430 --> 00:03:14.010
So unlike functions,

72
00:03:14.010 --> 00:03:16.860
when we try to access a var variable

73
00:03:16.860 --> 00:03:19.220
before it's declared in a code,

74
00:03:19.220 --> 00:03:21.760
we don't get the declared value

75
00:03:21.760 --> 00:03:23.980
but we get undefined.

76
00:03:23.980 --> 00:03:28.110
And this is a really weird behavior for beginners.

77
00:03:28.110 --> 00:03:31.080
You might expect that you simply get an error

78
00:03:31.080 --> 00:03:33.980
when using a variable before declaring it

79
00:03:33.980 --> 00:03:36.140
or to get the actual value.

80
00:03:36.140 --> 00:03:38.610
But not to get undefined

81
00:03:38.610 --> 00:03:42.300
because getting undefined is just really weird

82
00:03:42.300 --> 00:03:45.640
and it's not really useful either, right?

83
00:03:45.640 --> 00:03:47.500
And actually this behavior

84
00:03:47.500 --> 00:03:51.130
is a common source of bugs in JavaScript.

85
00:03:51.130 --> 00:03:53.230
So this is one of the main reasons

86
00:03:53.230 --> 00:03:55.060
why in modern JavaScript

87
00:03:55.060 --> 00:03:58.250
we almost never use var.

88
00:03:58.250 --> 00:03:59.550
Now on the other hand,

89
00:03:59.550 --> 00:04:03.680
let and const variables are not hoisted.

90
00:04:03.680 --> 00:04:07.060
I mean, technically they are actually hoisted

91
00:04:07.060 --> 00:04:11.120
but their value is basically set to an initialized.

92
00:04:11.120 --> 00:04:14.420
So there is no value to work with at all.

93
00:04:14.420 --> 00:04:17.410
And so in practice, it is as if hoisting

94
00:04:17.410 --> 00:04:19.950
was not happening at all.

95
00:04:19.950 --> 00:04:22.280
Instead, we say that these variables

96
00:04:22.280 --> 00:04:27.280
are placed in a so-called Temporal Dead Zone or TDZ

97
00:04:27.540 --> 00:04:30.700
which makes it so that we can't access the variables

98
00:04:30.700 --> 00:04:32.800
between the beginning of the scope

99
00:04:32.800 --> 00:04:36.600
and to place where the variables are declared.

100
00:04:36.600 --> 00:04:38.010
So as a consequence,

101
00:04:38.010 --> 00:04:41.380
if we attempt to use a let or const variable

102
00:04:41.380 --> 00:04:45.050
before it's declared, we get an error.

103
00:04:45.050 --> 00:04:49.620
Also keep in mind that let and const are block scoped.

104
00:04:49.620 --> 00:04:51.620
So they exist only in the block

105
00:04:51.620 --> 00:04:53.700
in which they were created.

106
00:04:53.700 --> 00:04:55.850
And all these factors together

107
00:04:55.850 --> 00:04:58.700
is basically the reason why let and const

108
00:04:58.700 --> 00:05:01.420
were first introduced into the language,

109
00:05:01.420 --> 00:05:04.130
and why we use them now instead of var

110
00:05:04.130 --> 00:05:06.450
in modern JavaScript.

111
00:05:06.450 --> 00:05:07.283
Okay.

112
00:05:07.283 --> 00:05:09.960
But now what about function expressions

113
00:05:09.960 --> 00:05:11.940
and arrow functions?

114
00:05:11.940 --> 00:05:14.710
How does hoisting work for this?

115
00:05:14.710 --> 00:05:17.270
Well, it depends if they were created

116
00:05:17.270 --> 00:05:20.540
using var or const or let.

117
00:05:20.540 --> 00:05:23.020
Because keep in mind that these functions

118
00:05:23.020 --> 00:05:24.790
are simply variables.

119
00:05:24.790 --> 00:05:27.460
And so they behave the exact same way

120
00:05:27.460 --> 00:05:30.940
as variables in regard to hoisting.

121
00:05:30.940 --> 00:05:33.220
This means that a function expression

122
00:05:33.220 --> 00:05:36.420
or arrow function created with var

123
00:05:36.420 --> 00:05:38.600
is hoisted to undefined.

124
00:05:38.600 --> 00:05:41.660
But if created with let or const,

125
00:05:41.660 --> 00:05:45.130
it's not usable before it's declared in a code

126
00:05:45.130 --> 00:05:48.150
because of the Temporal Dead Zone

127
00:05:48.150 --> 00:05:52.620
so again, just like normal variables, right?

128
00:05:52.620 --> 00:05:56.250
And this is actually the reason why I told you earlier

129
00:05:56.250 --> 00:05:58.840
that we cannot use function expressions

130
00:05:58.840 --> 00:06:01.450
before we write them in the code,

131
00:06:01.450 --> 00:06:03.823
unlike function declarations.

132
00:06:05.480 --> 00:06:06.380
Okay.

133
00:06:06.380 --> 00:06:08.320
But now before finishing,

134
00:06:08.320 --> 00:06:10.550
let's take a more detailed look

135
00:06:10.550 --> 00:06:14.020
at this mysterious Temporal Dead Zone.

136
00:06:14.020 --> 00:06:16.090
So in this example code

137
00:06:16.090 --> 00:06:19.620
we're gonna look at the job variable.

138
00:06:19.620 --> 00:06:24.210
It is a const so it's scoped only to this if block

139
00:06:24.210 --> 00:06:25.760
and it's gonna be accessible

140
00:06:25.760 --> 00:06:29.330
starting from the line where it's defined.

141
00:06:29.330 --> 00:06:30.490
Why?

142
00:06:30.490 --> 00:06:33.920
Well, because there is this Temporal Dead Zone

143
00:06:33.920 --> 00:06:36.130
for the job variable.

144
00:06:36.130 --> 00:06:38.230
It's basically the region of the scope

145
00:06:38.230 --> 00:06:40.540
in which the variable is defined,

146
00:06:40.540 --> 00:06:43.260
but can't be used in any way.

147
00:06:43.260 --> 00:06:47.650
So it is as if the variable didn't even exist.

148
00:06:47.650 --> 00:06:50.510
Now, if we still tried to access the variable

149
00:06:50.510 --> 00:06:53.390
while in the TDZ like we actually

150
00:06:53.390 --> 00:06:56.580
do in the first line of this if block,

151
00:06:56.580 --> 00:06:58.810
then we get a reference error

152
00:06:58.810 --> 00:07:01.170
telling us that we can't access job

153
00:07:01.170 --> 00:07:03.320
before initialization.

154
00:07:03.320 --> 00:07:04.970
So exactly as we learned

155
00:07:04.970 --> 00:07:06.823
in the last slide, right?

156
00:07:07.720 --> 00:07:10.773
However, if we tried to access a variable

157
00:07:10.773 --> 00:07:13.710
that was actually never even created,

158
00:07:13.710 --> 00:07:15.470
like in the last line here

159
00:07:15.470 --> 00:07:17.670
where we want to log x,

160
00:07:17.670 --> 00:07:20.090
then we get a different error message

161
00:07:20.090 --> 00:07:23.720
saying that x is not defined at all.

162
00:07:23.720 --> 00:07:25.820
What this means is that job is

163
00:07:25.820 --> 00:07:28.430
in fact in the Temporal Dead Zone

164
00:07:28.430 --> 00:07:30.550
where it is still initialized,

165
00:07:30.550 --> 00:07:32.370
but the engine knows that it will

166
00:07:32.370 --> 00:07:34.900
eventually be initialized

167
00:07:34.900 --> 00:07:37.610
because it already read the code before

168
00:07:37.610 --> 00:07:41.010
and set the job variable in the variable environment

169
00:07:41.010 --> 00:07:43.200
to uninitialized.

170
00:07:43.200 --> 00:07:45.530
Then when the execution reaches the line

171
00:07:45.530 --> 00:07:47.690
where the variable is declared,

172
00:07:47.690 --> 00:07:50.300
it is removed from the Temporal Dead Zone

173
00:07:50.300 --> 00:07:53.000
and it's then safe to use.

174
00:07:53.000 --> 00:07:56.130
So to recap, basically each and every

175
00:07:56.130 --> 00:07:58.540
let and const variable get their own

176
00:07:58.540 --> 00:08:00.570
Temporal Dead Zone that starts

177
00:08:00.570 --> 00:08:02.250
at the beginning of the scope

178
00:08:02.250 --> 00:08:05.180
until the line where it is defined.

179
00:08:05.180 --> 00:08:07.660
And the variable is only safe to use

180
00:08:07.660 --> 00:08:09.990
after the TDZ,

181
00:08:09.990 --> 00:08:12.740
so the Temporal Dead Zone.

182
00:08:12.740 --> 00:08:15.920
Alright, now what is actually the need

183
00:08:15.920 --> 00:08:19.480
for JavaScript to have a Temporal Dead Zone?

184
00:08:19.480 --> 00:08:22.320
Well, the main reason that the TDZ

185
00:08:22.320 --> 00:08:25.340
was introduced in ES6 is that

186
00:08:25.340 --> 00:08:27.490
the behavior I described before

187
00:08:27.490 --> 00:08:31.660
makes it way easier to avoid and catch errors.

188
00:08:31.660 --> 00:08:35.030
Because using a variable that is set to undefined

189
00:08:35.030 --> 00:08:37.150
before it's actually declared

190
00:08:37.150 --> 00:08:39.150
can cause serious bugs

191
00:08:39.150 --> 00:08:41.320
which might be hard to find.

192
00:08:41.320 --> 00:08:43.050
And I will show you a small example

193
00:08:43.050 --> 00:08:44.253
in the next lecture.

194
00:08:45.290 --> 00:08:48.430
So accessing variables before declaration

195
00:08:48.430 --> 00:08:51.650
is bad practice and should be avoided.

196
00:08:51.650 --> 00:08:53.530
And the best way to avoid it

197
00:08:53.530 --> 00:08:55.360
is by simply getting an error

198
00:08:55.360 --> 00:08:57.410
when we attempt to do so.

199
00:08:57.410 --> 00:09:00.653
And that's exactly what a Temporal Dead Zone does.

200
00:09:01.610 --> 00:09:05.880
A second and smaller reason why the TDZ exists

201
00:09:05.880 --> 00:09:07.570
is to make const variables

202
00:09:07.570 --> 00:09:10.770
actually work the way they are supposed to.

203
00:09:10.770 --> 00:09:14.560
So as you know, we can't reassign const variables.

204
00:09:14.560 --> 00:09:16.270
So it will not be possible

205
00:09:16.270 --> 00:09:18.350
to set them to undefined first

206
00:09:18.350 --> 00:09:21.700
and then assign their real value later.

207
00:09:21.700 --> 00:09:24.340
Const should never be reassigned.

208
00:09:24.340 --> 00:09:27.200
And so it's only assigned when execution

209
00:09:27.200 --> 00:09:30.090
actually reaches the declaration.

210
00:09:30.090 --> 00:09:31.690
And that makes it impossible

211
00:09:31.690 --> 00:09:34.160
to use the variable before.

212
00:09:34.160 --> 00:09:36.083
Okay? Makes sense?

213
00:09:37.000 --> 00:09:40.530
Now, if hoisting creates so many problems,

214
00:09:40.530 --> 00:09:43.720
why does it exist in the first place?

215
00:09:43.720 --> 00:09:45.720
I get this question all the time.

216
00:09:45.720 --> 00:09:48.660
And so let's quickly talk about that here.

217
00:09:48.660 --> 00:09:51.460
So the creator of JavaScript basically

218
00:09:51.460 --> 00:09:53.050
implemented hoisting

219
00:09:53.050 --> 00:09:55.480
so that we can use function declarations

220
00:09:55.480 --> 00:09:57.330
before we use them.

221
00:09:57.330 --> 00:09:58.930
Because this is essential

222
00:09:58.930 --> 00:10:01.020
for some programming techniques,

223
00:10:01.020 --> 00:10:03.570
such as mutual recursion.

224
00:10:03.570 --> 00:10:06.100
Some people also think that it makes code

225
00:10:06.100 --> 00:10:08.310
a lot more readable.

226
00:10:08.310 --> 00:10:12.220
Now, the fact that it also works for var declarations

227
00:10:12.220 --> 00:10:14.700
is because that was the only way hoisting

228
00:10:14.700 --> 00:10:17.390
could be implemented at the time.

229
00:10:17.390 --> 00:10:20.090
So the hoisting of var variables

230
00:10:20.090 --> 00:10:22.140
is basically just a byproduct

231
00:10:22.140 --> 00:10:24.290
of hoisting functions.

232
00:10:24.290 --> 00:10:27.000
And it probably seemed like a good idea

233
00:10:27.000 --> 00:10:29.860
to simply set variables to undefined,

234
00:10:29.860 --> 00:10:33.460
which in hindsight is not really that great.

235
00:10:33.460 --> 00:10:35.780
But we need to remember that JavaScript

236
00:10:35.780 --> 00:10:38.160
was never intended to become the huge

237
00:10:38.160 --> 00:10:41.090
programming language that it is today.

238
00:10:41.090 --> 00:10:43.350
Also, we can't remove this feature

239
00:10:43.350 --> 00:10:44.850
from the language now.

240
00:10:44.850 --> 00:10:48.323
And so we just use let and const to work around this.

241
00:10:49.610 --> 00:10:51.580
Alright, great.

242
00:10:51.580 --> 00:10:53.780
And with all that being said,

243
00:10:53.780 --> 00:10:57.573
let's now work on some practical hoisting examples.

