You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/06-advanced-functions/03-closure/article.md
+16-14Lines changed: 16 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -157,7 +157,7 @@ Now we can give the answer to the first seed question from the beginning of the
157
157
158
158
That's because of the described mechanism. Old variable values are not saved anywhere. When a function wants them, it takes the current values from its own or an outer Lexical Environment.
159
159
160
-
So the answer here is `Pete`:
160
+
So the answer to the first question is `Pete`:
161
161
162
162
```js run
163
163
let name ="John";
@@ -188,7 +188,7 @@ And if a function is called multiple times, then each invocation will have its o
188
188
```
189
189
190
190
```smart header="Lexical Environment is a specification object"
191
-
"Lexical Environment" is a specification object. We can't get this object in our code and manipulate it directly. JavaScript engines also may optimize it, discard variables that are unused to save memory and perform other internal tricks.
191
+
"Lexical Environment" is a specification object. We can't get this object in our code and manipulate it directly. JavaScript engines also may optimize it, discard variables that are unused to save memory and perform other internal tricks, but the visible behavior should be as described.
192
192
```
193
193
194
194
@@ -216,22 +216,22 @@ function sayHiBye(firstName, lastName) {
216
216
217
217
Here the *nested* function `getFullName()` is made for convenience. It can access the outer variables and so can return the full name.
218
218
219
-
What's more interesting, a nested function can be returned: as a property of a new object (if the outer function creates and returns it) or as a result by itself. And then used somewhere else. No matter where, it still keeps the access to the same outer variables.
219
+
What's more interesting, a nested function can be returned: as a property of a new object (if the outer function creates an object with methods) or as a result by itself. And then used somewhere else. No matter where, it still keeps the access to the same outer variables.
220
220
221
221
An example with the constructor function (see the chapter <info:constructor-new>):
222
222
223
223
```js run
224
224
// constructor function returns a new object
225
225
functionUser(name) {
226
226
227
-
// the method is created as a nested function
227
+
// the object method is created as a nested function
228
228
this.sayHi=function() {
229
229
alert(name);
230
230
};
231
231
}
232
232
233
233
let user =newUser("John");
234
-
user.sayHi();
234
+
user.sayHi();// the method code has access to the outer "name"
235
235
```
236
236
237
237
An example with returning a function:
@@ -241,7 +241,7 @@ function makeCounter() {
241
241
let count =0;
242
242
243
243
returnfunction() {
244
-
return count++;
244
+
return count++;// has access to the outer counter
245
245
};
246
246
}
247
247
@@ -252,13 +252,11 @@ alert( counter() ); // 1
252
252
alert( counter() ); // 2
253
253
```
254
254
255
-
Let's go on with the `makeCounter` example. It creates the "counter" function that returns the next number on each invocation. Despite being simple, slightly modified variants of that code have practical uses, for instance, as a [pseudorandom number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator), and more. So the example is not exactly "artificial".
256
-
257
-
How does the counter work?
255
+
Let's go on with the `makeCounter` example. It creates the "counter" function that returns the next number on each invocation. Despite being simple, slightly modified variants of that code have practical uses, for instance, as a [pseudorandom number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator), and more. So the example is not quite artificial.
258
256
259
-
When the inner function runs, the variable in `count++` is searched from inside out.
257
+
How does the counter work internally?
260
258
261
-
For the example above, the order will be:
259
+
When the inner function runs, the variable in `count++` is searched from inside out. For the example above, the order will be:
262
260
263
261

264
262
@@ -268,7 +266,7 @@ For the example above, the order will be:
268
266
269
267
In that example `count` is found on the step `2`. When an outer variable is modified, it's changed where it's found. So `count++` finds the outer variable and increases it in the Lexical Environment where it belongs. Like if we had `let count = 1`.
270
268
271
-
Here's a couple of questions:
269
+
Here are two questions for you:
272
270
273
271
1. Can we somehow reset the `counter` from the code that doesn't belong to `makeCounter`? E.g. after `alert` calls in the example above.
274
272
2. If we call `makeCounter()` multiple times -- it returns many `counter` functions. Are they independent or do they share the same `count`?
Probably, the situation with outer variables is quite clear for you as of now. But in more complex situations a deeper understanding of internals may be required. So here you go.
303
+
Probably, the situation with outer variables is quite clear for you as of now. But in more complex situations a deeper understanding of internals may be required. So let's go ahead.
306
304
307
305
## Environments in detail
308
306
309
-
For a more in-depth understanding, here's what's going on in the `makeCounter` example step-by-step, down to the nuts and bolts:
307
+
Now as you understand how closures work generally, we may finally descend to the very nuts and bolts.
308
+
309
+
Here's what's going on in the `makeCounter` example step-by-step, follow it to make sure that you understand everything. Please note the additional `[[Environment]]` property that we didn't cover yet.
310
310
311
311
1. When the script has just started, there is only global Lexical Environment:
312
312
@@ -318,6 +318,8 @@ For a more in-depth understanding, here's what's going on in the `makeCounter` e
318
318
319
319
Here, `makeCounter` is created in the global Lexical Environment, so `[[Environment]]` keeps the reference to it.
320
320
321
+
In other words, a function is "imprinted" with a reference to the Lexical Environment where it was born. And `[[Environment]]` is the hidden function property that has that reference.
322
+
321
323
2. Then the code runs on, and the call to `makeCounter()` is performed. Here's the picture for the moment when the execution is on the first line inside `makeCounter()`:
0 commit comments