Skip to content

Commit 83b93e5

Browse files
committed
up
1 parent 63f55dc commit 83b93e5

File tree

49 files changed

+689
-271
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+689
-271
lines changed

1-js/4-object-basics/04-object-methods/article.md

+23-1
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,11 @@ Please note that usually a call of a function using `this` without an object is
219219
```smart header="The consequences of unbound `this`"
220220
If you come from another programming languages, then you are probably used to an idea of a "bound `this`", where methods defined in an object always have `this` referencing that object.
221221

222-
The idea of unbound, run-time evaluated `this` has both pluses and minuses. From one side, a function can be reused for different objects. From the other side, greater flexibility opens a place for mistakes.
222+
The idea of unbound, run-time evaluated `this` has both pluses and minuses. From one side, a function can be reused for different objects. From the other side, greater flexibility opens a place for mistakes.
223223

224224
Here we are not to judge whether this language design decision is good or bad. We will understand how to work with it, how to get benefits and evade problems.
225225
```
226+
226227
## Internals: Reference Type
227228
228229
An intricate method call can loose `this`, for instance:
@@ -295,6 +296,27 @@ Any other operation like assignment `hi = user.hi` discards the reference type a
295296

296297
So, as the result, the value of `this` is only passed the right way if the function is called directly using a dot `obj.method()` or square brackets `obj[method]()` syntax (they do the same here).
297298

299+
````warn header="Arrow functions do not have `this`"
300+
Arrow functions are special: they don't have "own" `this`. If we reference `this` from such function, it's taken from the outer "normal" function.
301+
302+
For instance, here `arrow()` uses `this` from the outer `user.sayHi()` method:
303+
304+
```js run
305+
let user = {
306+
firstName: "Ilya",
307+
sayHi() {
308+
let arrow = () => alert(this.firstName);
309+
arrow();
310+
}
311+
};
312+
313+
user.sayHi(); // Ilya
314+
```
315+
316+
That's a special feature of arrow functions, it's useful when we actually do not want to have a separate `this`, but rather to take it from the outer context. Later in the chapter <info:arrow-functions> we'll dig more deeply into what's going on.
317+
318+
````
319+
298320
## Summary
299321
300322
[todo]

1-js/5-data-types/01-primitives-methods/article.md

+33
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,39 @@ alert( n.toFixed(2) ); // 1.23
8181

8282
We'll see more specific methods in chapters <info:number> and <info:string>.
8383

84+
85+
````warn header="Constructors `String/Number/Boolean` are for internal use only"
86+
Some languages like Java allow to create "wrapper objects" for primitives explicitly using syntax like `new Number(1)` or `new Boolean(false)`.
87+
88+
In Javascript that's also possible for historical reasons, but highly not recommended. Things will go crazy in many places.
89+
90+
For instance:
91+
92+
```js run
93+
alert( typeof 1 ); // "number"
94+
95+
alert( typeof new Number(1) ); // "object"!
96+
```
97+
98+
And, because `zero` is an object:
99+
100+
```js run
101+
let zero = new Number(0);
102+
103+
if (zero) { // zero is true, because it's an object
104+
alert( "zero is truthy?!?" );
105+
}
106+
```
107+
108+
From the other side, using same functions `String/Number/Boolean` without `new` is a totally sane and useful thing. They convert a value to the corresponding type: to a string, a number, or a boolean (primitive).
109+
110+
This is totally valid:
111+
```js
112+
let num = Number("123"); // convert a string to number
113+
```
114+
````
115+
116+
84117
````warn header="null/undefined have no methods"
85118
Special primitives `null` and `undefined` are exceptions. They have no corresponding "wrapper objects" and provide no methods. In a sense, they are "the most primitive".
86119

1-js/5-data-types/05-array-methods/article.md

+12-13
Original file line numberDiff line numberDiff line change
@@ -606,32 +606,31 @@ alert(typeof {}); // object
606606
alert(typeof []); // same
607607
```
608608

609-
There's a special method for that [Array.isArray(value)](mdn:js/Array/isArray) that returns `true` if the `value` is an array, and `false` otherwise.
609+
...But arrays are used so often that there's a special method for that: [Array.isArray(value)](mdn:js/Array/isArray). It returns `true` if the `value` is an array, and `false` otherwise.
610610

611611
```js run
612612
alert(Array.isArray({})); // false
613613

614614
alert(Array.isArray([])); // true
615615
```
616616

617-
```smart header="`Array.isArray` vs other type-checks"
618-
You remembeare other ways to check for
619-
620617
## Methods: "thisArg"
621618

622619
Almost all array methods that call functions -- like `find`, `filter`, `map`, with a notable exception of `sort`, accept an optional additional parameter `thisArg`.
623620

624-
The full syntax is:
621+
In the sections above that parameter is not explained, because it's rarely used.
622+
623+
But for completeness here's the full syntax:
625624

626625
```js
627-
let result = arr.find(func, thisArg);
628-
let results = arr.filter(func, thisArg);
629-
// etc, thisArg goes after the function
626+
arr.find(func, thisArg);
627+
arr.filter(func, thisArg);
628+
arr.map(func, thisArg);
629+
// ...
630+
// thisArg is the optional last argument
630631
```
631632

632-
It is used sparingly, but we have to cover it here for the sake of completeness.
633-
634-
The value of `thisArg` parameter becomes `this` for the function.
633+
The value of `thisArg` parameter becomes `this` for `func`.
635634

636635
For instance, here we use an object method as a filter:
637636

@@ -657,7 +656,7 @@ let youngerUsers = users.filter(user.younger, user);
657656
alert(youngerUsers.length); // 2
658657
```
659658

660-
In the call above, we use `user.younger` as a filter and also provide `user` as the context for it. If we did't provide the context, `users.filter(user.younger)` would call `user.younger` as a standalone function, with `this=undefined`. That would be an instant error.
659+
In the call above, we use `user.younger` as a filter and also provide `user` as the context for it. If we did't provide the context, `users.filter(user.younger)` would call `user.younger` as a standalone function, with `this=undefined`. That would mean an instant error.
661660

662661
## Other methods
663662

@@ -676,7 +675,7 @@ These and other methods are also listed in the [manual](mdn:js/Array).
676675

677676
## Summary
678677

679-
Most often methods:
678+
Most used array methods:
680679

681680
- `split/join` -- convert a string to array and back.
682681
- `splice` -- delete and insert elements at the given position.

1-js/8-more-functions/02-rest-parameters-spread-operator/article.md

+17
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,23 @@ Also, it always has all arguments in it, we can't capture them partially, like w
107107

108108
So when we need these features, then rest parameters are preferred.
109109

110+
````smart header="Arrow functions do not have `\"arguments\"`"
111+
If we access the `arguments` object from an arrow function, it takes them from the outer "normal" function.
112+
113+
Here's an example:
114+
115+
```js run
116+
function f() {
117+
let showArg = () => alert(arguments[0]);
118+
showArg();
119+
}
120+
121+
f(1); // 1
122+
```
123+
As we remember, arrow functions don't have own `this`. Now we know they don't have the special `arguments` object too.
124+
125+
````
126+
110127
## Spread operator [#spread-operator]
111128
112129
We've just seen how to get an array from the list of parameters.

1-js/8-more-functions/03-closure/2-counter-object-independent/solution.md

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

2-
Both nested functions are created within the same Lexical Environment.
2+
Surely it will work just fine.
33

4-
So they share the same `count`:
4+
Both nested functions are created within the same outer Lexical Environment, so they share access to the same `count` variable:
55

66
```js run
77
function Counter() {
@@ -10,6 +10,7 @@ function Counter() {
1010
this.up = function() {
1111
return ++count;
1212
};
13+
1314
this.down = function() {
1415
return --count;
1516
};
Original file line numberDiff line numberDiff line change
@@ -1,33 +1 @@
1-
Решение аналогично задаче <info:task/logging-decorator>, разница в том, что в лог вместо одного аргумента идет весь объект `arguments`.
2-
3-
Для передачи вызова с произвольным количеством аргументов используем `f.apply(this, arguments)`.
4-
5-
```js run
6-
function work(a, b) {
7-
alert( a + b ); // work - произвольная функция
8-
}
9-
10-
function makeLogging(f, log) {
11-
12-
*!*
13-
function wrapper() {
14-
log.push([].slice.call(arguments));
15-
return f.apply(this, arguments);
16-
}
17-
*/!*
18-
19-
return wrapper;
20-
}
21-
22-
var log = [];
23-
work = makeLogging(work, log);
24-
25-
work(1, 2); // 3
26-
work(4, 5); // 9
27-
28-
for (var i = 0; i < log.length; i++) {
29-
var args = log[i]; // массив из аргументов i-го вызова
30-
alert( 'Лог:' + args.join() ); // "Лог:1,2", "Лог:4,5"
31-
}
32-
```
33-
1+
Here we can use `log.push(args)` to store all arguments in the log and `f.apply(this, args)` to forward the call.

1-js/8-more-functions/08-call-apply-decorators/article.md

-1
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,6 @@ Taken from the specification almost "as-is":
434434

435435
So, technically it takes `this` and joins `this[0]`, `this[1]` ...etc together. It's intentionally written in a way that allows any array-like `this` (not a coincidence, many methods follow this practice). That's why it also works with `this=arguments`.
436436

437-
438437
## Summary
439438

440439
*Decorator* is a wrapper around a function that alters its behavior. The main job is still carried out by the function.

1-js/8-more-functions/09-bind/article.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ let f = user.sayHi;
3939
setTimeout(f, 1000); // lost user context
4040
```
4141

42-
The method `setTimeout` is a little special: it sets `this=window` for the function call. So for `this.firstName` it tries to get `window.firstName`, which does not exist. In other similar cases as we'll see, usually `this` just becomes `undefined`.
42+
The method `setTimeout` in-browser is a little special: it sets `this=window` for the function call (for Node.JS, `this` becomes the timer object, but doesn't really matter here). So for `this.firstName` it tries to get `window.firstName`, which does not exist. In other similar cases as we'll see, usually `this` just becomes `undefined`.
4343

4444
The task is quite typical -- we want to pass an object method somewhere else (here -- to the scheduler) where it will be called. How to make sure that it will be called in the right context?
4545

@@ -494,4 +494,4 @@ But most implementations of currying in Javascript are advanced, as described: t
494494
495495
- *Currying* is a transform that makes `f(a,b,c)` callable as `f(a)(b)(c)`. Javascript implementations usually both keep the function callable normally and return the partial if arguments count is not enough.
496496
497-
Currying is convenient when we want to have easy partials. We saw an example with logging: the universal function `log(date, importance, message)` after currying gives us partials when called with one argument like `log(date)` or two arguments `log(date, importance)`.
497+
Currying is great when we want easy partials. As we've seen in the logging example: the universal function `log(date, importance, message)` after currying gives us partials when called with one argument like `log(date)` or two arguments `log(date, importance)`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Arrow functions revisited
2+
3+
Let's revisit arrow functions.
4+
5+
[cut]
6+
7+
Arrow functions are not just a "shorthand" for writing small stuff.
8+
9+
Javascript is full of situations where we need to write a small function, that's executed somewhere else.
10+
11+
For instance:
12+
13+
- `arr.forEach(func)` -- `func` is executed by `forEach` for every array item.
14+
- `setTimeout(func)` -- `func` is executed by the built-in scheduler.
15+
- ...there are more.
16+
17+
It's very in the spirit of Javascript to create a function and pass it somewhere.
18+
19+
And in such functions we usually don't want to leave the current context.
20+
21+
## Arrow functions have no "this"
22+
23+
As we remember from the chapter <info:object-methods>, arrow functions do not have `this`. If `this` is accessed, it is taken from the outside.
24+
25+
For instance, we can use it to iterate inside an object method:
26+
27+
```js run
28+
let group = {
29+
title: "Our Group",
30+
students: ["John", "Pete", "Alice"],
31+
32+
showList() {
33+
*!*
34+
this.students.forEach(
35+
student => alert(this.title + ': ' + student)
36+
);
37+
*/!*
38+
}
39+
};
40+
41+
group.showList();
42+
```
43+
44+
Here in `forEach`, the arrow function is used, so `this.title` in it is exactly the same as in the outer method `showList`. That is: `group.title`.
45+
46+
If we used a "regular" function, there would be an error:
47+
48+
```js run
49+
let group = {
50+
title: "Our Group",
51+
students: ["John", "Pete", "Alice"],
52+
53+
showList() {
54+
*!*
55+
this.students.forEach(function(student) {
56+
// Error: Cannot read property 'title' of undefined
57+
alert(this.title + ': ' + student)
58+
});
59+
*/!*
60+
}
61+
};
62+
63+
group.showList();
64+
```
65+
66+
The error occurs because `forEach` runs functions with `this=undefined` by default, so the attempt to access `undefined.title` is made.
67+
68+
That doesn't affect arrow functions, because they just don't have `this`.
69+
70+
```warn header="Arrow functions can't run with `new`"
71+
Not having `this` naturally means another limitation: arrow functions can't be used as constructors. They can't be called with `new`.
72+
```
73+
74+
```smart header="Arrow functions VS bind"
75+
There's a subtle difference between an arrow function `=>` and a regular function called with `.bind(this)`:
76+
77+
- `.bind(this)` creates a "bound version" of the function.
78+
- The arrow `=>` doesn't create any binding. The function simply doesn't have `this`. The lookup of `this` is made exactly the same way as a regular variable search: in the outer lexical environment.
79+
```
80+
81+
## Arrows have no "arguments"
82+
83+
Arrow functions also have no `arguments` variable.
84+
85+
That's great for decorators, when we need to forward a call with the current `this` and `arguments`.
86+
87+
For instance, `defer(f, ms)` gets a function and returns a wrapper around it that delays the call by `ms` milliseconds:
88+
89+
```js run
90+
function defer(f, ms) {
91+
return function() {
92+
setTimeout(() => f.apply(this, arguments), ms)
93+
};
94+
}
95+
96+
function sayHi(who) {
97+
alert('Hello, ' + who);
98+
}
99+
100+
let sayHiDeferred = defer(sayHi, 2000);
101+
sayHiDeferred("John"); // Hello, John after 2 seconds
102+
```
103+
104+
The same without an arrow function would look like:
105+
106+
Аналогичная реализация без функции-стрелки выглядела бы так:
107+
108+
```js
109+
function defer(f, ms) {
110+
return function(...args) {
111+
let ctx = this;
112+
setTimeout(function() {
113+
return f.apply(ctx, args);
114+
}, ms);
115+
};
116+
}
117+
```
118+
119+
Here we had to create additional variables `args` and `ctx` so that the function inside `setTimeout` could take them.
120+
121+
## Summary
122+
123+
Arrow functions:
124+
125+
- Do not have `this`.
126+
- Do not have `arguments`.
127+
- Can't be called with `new`.
128+
- (They also don't have `super`, but we didn't study it. Will be in the chapter <info:class-inheritance>).
129+
130+
That's because they are meant for short pieces of code that does not have the own "context", but rather works in the current one. And they really shine in that use case.

1-js/9-object-inheritance/04-function-prototype/article.md

+3-5
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,13 @@ That's handy when we have an object, don't know which constructor was used for i
108108

109109
...But probably the most important thing about `"constructor"` is that...
110110

111-
**JavaScript itself does not use the `"constructor"` property at all.**
111+
**JavaScript itself does not ensure the right `"constructor"` at all.**
112112

113-
Yes, it exists in the default `"prototype"` for functions, but that's literally all about it. No language function relies on it and nothing controls its validity.
114-
115-
It is created automatically, but what happens with it later -- is totally on us.
113+
Yes, it exists in the default `"prototype"` for functions, but that's all. It is created automatically, but what happens with it later -- is totally on us.
116114

117115
In particular, if we replace the default prototype by assigning our own `Rabbit.prototype = { jumps: true }`, then there will be no `"constructor"` in it.
118116

119-
Such assignment won't break native methods or syntax, because nothing in the language uses the `"constructor"` property. But we may want to keep `"constructor"` for convenience by adding properties to the default `"prototype"` instead of overwriting it as a whole:
117+
But we may want to keep `"constructor"` for convenience by adding properties to the default `"prototype"` instead of overwriting it as a whole:
120118

121119
```js
122120
function Rabbit() {}
Loading
Loading
Loading
Loading

0 commit comments

Comments
 (0)