Skip to content

Commit b6adf0b

Browse files
committed
up
1 parent 4e9f302 commit b6adf0b

File tree

9 files changed

+51
-106
lines changed

9 files changed

+51
-106
lines changed

1-js/06-advanced-functions/03-closure/article.md

+22-25
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ So, during the function call we have two Lexical Environments: the inner one (fo
143143
It has a single property: `name`, the function argument. We called `say("John")`, so the value of `name` is `"John"`.
144144
- The outer Lexical Environment is the global Lexical Environment.
145145
146-
It has `phrase` and the function itself.
146+
It has `phrase` variable and the function itself.
147147
148-
The inner Lexical Environment has a reference to the outer one.
148+
The inner Lexical Environment has a reference to the `outer` one.
149149
150150
**When the code wants to access a variable -- the inner Lexical Environment is searched first, then the outer one, then the more outer one and so on until the global one.**
151151
@@ -160,9 +160,9 @@ Let's see how the search proceeds in our example:
160160
161161
Now we can give the answer to the first question from the beginning of the chapter.
162162
163-
**A function gets outer variables as they are now; it uses the most recent values.**
163+
**A function gets outer variables as they are now, it uses the most recent values.**
164164
165-
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.
165+
Old variable values are not saved anywhere. When a function wants a variable, it takes the current value from its own Lexical Environment or the outer one.
166166
167167
So the answer to the first question is `Pete`:
168168
@@ -309,7 +309,7 @@ alert( counter2() ); // 0 (independent)
309309
```
310310

311311

312-
Hopefully, the situation with outer variables is clear now. For most situations such understanding is enough. There are few details in the specification that we omitted for brevity. So in the next section we cover even more details, not to miss anything.
312+
Hopefully, the situation with outer variables is clear now. For most situations such understanding is enough. There are few details in the specification that we omitted for brevity. So in the next section we cover even more details.
313313

314314
## Environments in detail
315315

@@ -323,21 +323,23 @@ Please note the additional `[[Environment]]` property is covered here. We didn't
323323

324324
At that starting moment there is only `makeCounter` function, because it's a Function Declaration. It did not run yet.
325325

326-
**All functions "on birth" receive a hidden property `[[Environment]]` with a reference to the Lexical Environment of their creation.** We didn't talk about it yet, but that's how the function knows where it was made.
326+
**All functions "on birth" receive a hidden property `[[Environment]]` with a reference to the Lexical Environment of their creation.**
327+
328+
We didn't talk about it yet, that's how the function knows where it was made.
327329

328330
Here, `makeCounter` is created in the global Lexical Environment, so `[[Environment]]` keeps a reference to it.
329331

330332
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.
331333

332-
2. The code runs on, the new global variable `counter` is declared and for its value `makeCounter()` is called. Here's a snapshot of the moment when the execution is on the first line inside `makeCounter()`:
334+
2. The code runs on, the new global variable `counter` is declared and gets the result of `makeCounter()` call. Here's a snapshot of the moment when the execution is on the first line inside `makeCounter()`:
333335

334336
![](lexenv-nested-makecounter-2.svg)
335337

336338
At the moment of the call of `makeCounter()`, the Lexical Environment is created, to hold its variables and arguments.
337339

338340
As all Lexical Environments, it stores two things:
339341
1. An Environment Record with local variables. In our case `count` is the only local variable (appearing when the line with `let count` is executed).
340-
2. The outer lexical reference, which is set to `[[Environment]]` of the function. Here `[[Environment]]` of `makeCounter` references the global Lexical Environment.
342+
2. The outer lexical reference, which is set to the value of `[[Environment]]` of the function. Here `[[Environment]]` of `makeCounter` references the global Lexical Environment.
341343

342344
So, now we have two Lexical Environments: the first one is global, the second one is for the current `makeCounter` call, with the outer reference to global.
343345

@@ -357,13 +359,11 @@ Please note the additional `[[Environment]]` property is covered here. We didn't
357359

358360
That function has only one line: `return count++`, that will be executed when we run it.
359361

360-
5. When the `counter()` is called, an "empty" Lexical Environment is created for it. It has no local variables by itself. But the `[[Environment]]` of `counter` is used as the outer reference for it, so it has access to the variables of the former `makeCounter()` call where it was created:
362+
5. When `counter()` is called, a new Lexical Environment is created for the call. It's empty, as `counter` has no local variables by itself. But the `[[Environment]]` of `counter` is used as the `outer` reference for it, that provides has access to the variables of the former `makeCounter()` call where it was created:
361363

362364
![](lexenv-nested-makecounter-5.svg)
363365

364-
Now if it accesses a variable, it first searches its own Lexical Environment (empty), then the Lexical Environment of the former `makeCounter()` call, then the global one.
365-
366-
When it looks for `count`, it finds it among the variables `makeCounter`, in the nearest outer Lexical Environment.
366+
Now when the call looks for `count` variable, it first searches its own Lexical Environment (empty), then the Lexical Environment of the outer `makeCounter()` call, where finds it.
367367

368368
Please note how memory management works here. Although `makeCounter()` call finished some time ago, its Lexical Environment was retained in memory, because there's a nested function with `[[Environment]]` referencing it.
369369

@@ -373,13 +373,11 @@ Please note the additional `[[Environment]]` property is covered here. We didn't
373373

374374
![](lexenv-nested-makecounter-6.svg)
375375

376-
So we return to the previous step with the only change -- the new value of `count`. The following calls all do the same.
377-
378376
7. Next `counter()` invocations do the same.
379377

380378
The answer to the second question from the beginning of the chapter should now be obvious.
381379

382-
The `work()` function in the code below uses the `name` from the place of its origin through the outer lexical environment reference:
380+
The `work()` function in the code below gets `name` from the place of its origin through the outer lexical environment reference:
383381

384382
![](lexenv-nested-work.svg)
385383

@@ -430,7 +428,7 @@ For instance, after `if` finishes, the `alert` below won't see the `user`, hence
430428

431429
### For, while
432430

433-
For a loop, every iteration has a separate Lexical Environment. If a variable is declared in `for`, then it's also local to that Lexical Environment:
431+
For a loop, every iteration has a separate Lexical Environment. If a variable is declared in `for(let ...)`, then it's also in there:
434432

435433
```js run
436434
for (let i = 0; i < 10; i++) {
@@ -441,7 +439,7 @@ for (let i = 0; i < 10; i++) {
441439
alert(i); // Error, no such variable
442440
```
443441

444-
Please note: `let i` is visually outside of `{...}`. The `for` construct is somewhat special here: each iteration of the loop has its own Lexical Environment with the current `i` in it.
442+
Please note: `let i` is visually outside of `{...}`. The `for` construct is special here: each iteration of the loop has its own Lexical Environment with the current `i` in it.
445443

446444
Again, similarly to `if`, after the loop `i` is not visible.
447445

@@ -537,7 +535,7 @@ There exist other ways besides parentheses to tell JavaScript that we mean a Fun
537535
}();
538536
```
539537

540-
In all the above cases we declare a Function Expression and run it immediately.
538+
In all the above cases we declare a Function Expression and run it immediately. Let's note again: nowadays there's no reason to write such code.
541539

542540
## Garbage collection
543541

@@ -554,7 +552,7 @@ f();
554552

555553
Here two values are technically the properties of the Lexical Environment. But after `f()` finishes that Lexical Environment becomes unreachable, so it's deleted from the memory.
556554

557-
...But if there's a nested function that is still reachable after the end of `f`, then its `[[Environment]]` reference keeps the outer lexical environment alive as well:
555+
...But if there's a nested function that is still reachable after the end of `f`, then it has `[[Environment]]` property that references the outer lexical environment, so it's also reachable and alive:
558556

559557
```js
560558
function f() {
@@ -570,7 +568,7 @@ function f() {
570568
let g = f(); // g is reachable, and keeps the outer lexical environment in memory
571569
```
572570

573-
Please note that if `f()` is called many times, and resulting functions are saved, then the corresponding Lexical Environment objects will also be retained in memory. All 3 of them in the code below:
571+
Please note that if `f()` is called many times, and resulting functions are saved, then all corresponding Lexical Environment objects will also be retained in memory. All 3 of them in the code below:
574572

575573
```js
576574
function f() {
@@ -579,9 +577,8 @@ function f() {
579577
return function() { alert(value); };
580578
}
581579

582-
// 3 functions in array, every one of them links to Lexical Environment (LE for short)
580+
// 3 functions in array, every one of them links to Lexical Environment
583581
// from the corresponding f() run
584-
// LE LE LE
585582
let arr = [f(), f(), f()];
586583
```
587584

@@ -608,7 +605,7 @@ g = null; // ...and now the memory is cleaned up
608605

609606
As we've seen, in theory while a function is alive, all outer variables are also retained.
610607

611-
But in practice, JavaScript engines try to optimize that. They analyze variable usage and if it's easy to see that an outer variable is not used -- it is removed.
608+
But in practice, JavaScript engines try to optimize that. They analyze variable usage and if it's obvious from the code that an outer variable is not used -- it is removed.
612609

613610
**An important side effect in V8 (Chrome, Opera) is that such variable will become unavailable in debugging.**
614611

@@ -621,7 +618,7 @@ function f() {
621618
let value = Math.random();
622619

623620
function g() {
624-
debugger; // in console: type alert( value ); No such variable!
621+
debugger; // in console: type alert(value); No such variable!
625622
}
626623

627624
return g;
@@ -642,7 +639,7 @@ function f() {
642639
let value = "the closest value";
643640

644641
function g() {
645-
debugger; // in console: type alert( value ); Surprise!
642+
debugger; // in console: type alert(value); Surprise!
646643
}
647644

648645
return g;

1-js/06-advanced-functions/05-global-object/article.md

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
11

22
# Global object
33

4-
The global object provides variables and functions that are available anywhere. Mostly, the ones that are built into the language or the environment.
4+
The global object provides variables and functions that are available anywhere. By default, those that are built into the language or the environment.
55

66
In a browser it is named `window`, for Node.js it is `global`, for other environments it may have another name.
77

88
Recently, `globalThis` was added to the language, as a standartized name for a global object, that should be supported across all environments. In some browsers, namely non-Chromium Edge, `globalThis` is not yet supported, but can be easily polyfilled.
99

10+
We'll use `window` here, assuming that our environment is a browser. If your script may run in other environments, it's better to use `globalThis` instead.
11+
1012
All properties of the global object can be accessed directly:
1113

1214
```js run
1315
alert("Hello");
14-
15-
// the same as
16+
// is the same as
1617
window.alert("Hello");
1718
```
1819

19-
In a browser, global functions and variables declared with `var` become the property of the global object:
20+
In a browser, global functions and variables declared with `var` (not `let/const`!) become the property of the global object:
2021

2122
```js run untrusted refresh
2223
var gVar = 5;
2324

2425
alert(window.gVar); // 5 (became a property of the global object)
2526
```
2627

27-
Please don't rely on that! This behavior exists for compatibility reasons. Modern scripts use JavaScript modules where such thing doesn't happen. We'll cover them later in the chapter [](info:modules).
28+
Please don't rely on that! This behavior exists for compatibility reasons. Modern scripts use [JavaScript modules](info:modules) where such thing doesn't happen.
2829

29-
Also, more modern variable declarations `let` and `const` do not exhibit such behavior at all:
30+
If we used `let` instead, such thing wouldn't happen:
3031

3132
```js run untrusted refresh
3233
let gLet = 5;
@@ -52,7 +53,7 @@ alert(currentUser.name); // John
5253
alert(window.currentUser.name); // John
5354
```
5455

55-
That said, using global variables is generally discouraged. There should be as few global variables as possible. The code design where a function gets "input" variables and produces certain "outcome" is clearer, less prone to errors and easier to test.
56+
That said, using global variables is generally discouraged. There should be as few global variables as possible. The code design where a function gets "input" variables and produces certain "outcome" is clearer, less prone to errors and easier to test than if it uses outer or global variables.
5657

5758
## Using for polyfills
5859

1-js/06-advanced-functions/06-function-object/2-counter-inc-dec/task.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ importance: 5
77
Modify the code of `makeCounter()` so that the counter can also decrease and set the number:
88

99
- `counter()` should return the next number (as before).
10-
- `counter.set(value)` should set the `count` to `value`.
11-
- `counter.decrease()` should decrease the `count` by 1.
10+
- `counter.set(value)` should set the counter to `value`.
11+
- `counter.decrease()` should decrease the counter by 1.
1212

1313
See the sandbox code for the complete usage example.
1414

1-js/06-advanced-functions/06-function-object/article.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
# Function object, NFE
33

4-
As we already know, functions in JavaScript are values.
4+
As we already know, a function in JavaScript is a value.
55

66
Every value in JavaScript has a type. What type is a function?
77

@@ -12,7 +12,7 @@ A good way to imagine functions is as callable "action objects". We can not only
1212

1313
## The "name" property
1414

15-
Function objects contain a few useable properties.
15+
Function objects contain some useable properties.
1616

1717
For instance, a function's name is accessible as the "name" property:
1818

@@ -24,14 +24,14 @@ function sayHi() {
2424
alert(sayHi.name); // sayHi
2525
```
2626

27-
What's more funny, the name-assigning logic is smart. It also assigns the correct name to functions that are used in assignments:
27+
What's kind of funny, the name-assigning logic is smart. It also assigns the correct name to a function even it's created without one, and then immediately assigned:
2828

2929
```js run
3030
let sayHi = function() {
3131
alert("Hi");
32-
}
32+
};
3333

34-
alert(sayHi.name); // sayHi (works!)
34+
alert(sayHi.name); // sayHi (there's a name!)
3535
```
3636

3737
It also works if the assignment is done via a default value:
@@ -93,7 +93,7 @@ alert(many.length); // 2
9393

9494
Here we can see that rest parameters are not counted.
9595

96-
The `length` property is sometimes used for introspection in functions that operate on other functions.
96+
The `length` property is sometimes used for [introspection](https://en.wikipedia.org/wiki/Type_introspection) in functions that operate on other functions.
9797

9898
For instance, in the code below the `ask` function accepts a `question` to ask and an arbitrary number of `handler` functions to call.
9999

@@ -102,9 +102,9 @@ Once a user provides their answer, the function calls the handlers. We can pass
102102
- A zero-argument function, which is only called when the user gives a positive answer.
103103
- A function with arguments, which is called in either case and returns an answer.
104104

105-
The idea is that we have a simple, no-arguments handler syntax for positive cases (most frequent variant), but are able to provide universal handlers as well.
105+
To call `handler` the right way, we examine the `handler.length` property.
106106

107-
To call `handlers` the right way, we examine the `length` property:
107+
The idea is that we have a simple, no-arguments handler syntax for positive cases (most frequent variant), but are able to support universal handlers as well:
108108

109109
```js run
110110
function ask(question, ...handlers) {
@@ -241,7 +241,7 @@ let sayHi = function *!*func*/!*(who) {
241241
sayHi("John"); // Hello, John
242242
```
243243

244-
There are two special things about the name `func`:
244+
There are two special things about the name `func`, that are the reasons for it:
245245

246246
1. It allows the function to reference itself internally.
247247
2. It is not visible outside of the function.
@@ -347,6 +347,6 @@ If the function is declared as a Function Expression (not in the main code flow)
347347

348348
Also, functions may carry additional properties. Many well-known JavaScript libraries make great use of this feature.
349349

350-
They create a "main" function and attach many other "helper" functions to it. For instance, the [jquery](https://jquery.com) library creates a function named `$`. The [lodash](https://lodash.com) library creates a function `_`. And then adds `_.clone`, `_.keyBy` and other properties to (see the [docs](https://lodash.com/docs) when you want learn more about them). Actually, they do it to lessen their pollution of the global space, so that a single library gives only one global variable. That reduces the possibility of naming conflicts.
350+
They create a "main" function and attach many other "helper" functions to it. For instance, the [jQuery](https://jquery.com) library creates a function named `$`. The [lodash](https://lodash.com) library creates a function `_`. And then adds `_.clone`, `_.keyBy` and other properties to (see the [docs](https://lodash.com/docs) when you want learn more about them). Actually, they do it to lessen their pollution of the global space, so that a single library gives only one global variable. That reduces the possibility of naming conflicts.
351351

352352
So, a function can do a useful job by itself and also carry a bunch of other functionality in properties.

1-js/06-advanced-functions/07-new-function/article.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,13 @@ It is used in very specific cases, like when we receive code from a server, or t
4646

4747
## Closure
4848

49-
Usually, a function remembers where it was born in the special property `[[Environment]]`. It references the Lexical Environment from where it's created.
49+
Usually, a function remembers where it was born in the special property `[[Environment]]`. It references the Lexical Environment from where it's created (we covered that in the chapter <info:closure>).
5050

51-
But when a function is created using `new Function`, its `[[Environment]]` references not the current Lexical Environment, but instead the global one.
51+
But when a function is created using `new Function`, its `[[Environment]]` is set to reference not the current Lexical Environment, but the global one.
5252

5353
So, such function doesn't have access to outer variables, only to the global ones.
5454

5555
```js run
56-
5756
function getFunc() {
5857
let value = "test";
5958

@@ -99,6 +98,8 @@ So if `new Function` had access to outer variables, it would be unable to find r
9998

10099
**If `new Function` had access to outer variables, it would have problems with minifiers.**
101100

101+
Besides, such code would be architecturally bad and prone to errors.
102+
102103
To pass something to a function, created as `new Function`, we should use its arguments.
103104

104105
## Summary
@@ -111,12 +112,12 @@ let func = new Function ([arg1, arg2, ...argN], functionBody);
111112

112113
For historical reasons, arguments can also be given as a comma-separated list.
113114

114-
These three lines mean the same:
115+
These three declarations mean the same:
115116

116117
```js
117118
new Function('a', 'b', 'return a + b'); // basic syntax
118119
new Function('a,b', 'return a + b'); // comma-separated
119120
new Function('a , b', 'return a + b'); // comma-separated with spaces
120121
```
121122

122-
Functions created with `new Function`, have `[[Environment]]` referencing the global Lexical Environment, not the outer one. Hence, they cannot use outer variables. But that's actually good, because it saves us from errors. Passing parameters explicitly is a much better method architecturally and causes no problems with minifiers.
123+
Functions created with `new Function`, have `[[Environment]]` referencing the global Lexical Environment, not the outer one. Hence, they cannot use outer variables. But that's actually good, because it insures us from errors. Passing parameters explicitly is a much better method architecturally and causes no problems with minifiers.

0 commit comments

Comments
 (0)